PNK
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
VERSION
$Id: PNK.nlogo 39722 2008-05-01 18:38:33Z everreau $
WHAT IS IT?
This model is a simple implementation of a "real-time strategy" type game. It is designed to teach NetLogo and be fun (in that order.) It is a strictly HubNet model. The idea is that students represent competing armies in the playing field. The goal is to capture all of the bases (by attacking them and thus winning them to your side.) The player can command three different types of units: pirates, knights, and ninjas. They have special attributes as follows:
Pirates are slow. However, when they attack, they damage all enemy units in range, not just the specific unit they are attacking.
Knights are medium speed. They are considered to be helpful knights, and thus automatically heal nearby friendly units.
Ninjas are very quick, but can't attack bases. They have ninja magic, however, that allows them to disappear and reappear at will. Other units can still attack invisible ninjas, but the user obviously doesn't know where they are.
More tradition RTS games are controlled by selecting a unit with the mouse and giving it commands. PKN is instead controlled by issuing NetLogo commands to each type of unit. Individual units are not selectable; strategies automatically apply to the entire unit type. (There are ways to programmatically command half of the pirates attack bases, for example, while the other half defends your own bases.) While a basic strategy requires no more NetLogo knowledge than using the provided attack-any and defend-any commands, more advanced strategies naturally require more advanced NetLogo mastery.
HOW IT WORKS
At each timestep, all of the units perform the actions stored in their "plan". While the simulation is running (or paused), the user can click one of the buttons to get a copy of that unit's current plan. The user can then modify the plan, and hit the done button to submit it back to the server. From then on, the user's units will perform the new plan. This allows the user to adopt a general strategy (attack the opponents' bases), but also react to current developments (defend your especially endangered base.) Once all of the units of a player are destroyed, that player is done. When only one player remains, the game is over.
HOW TO USE IT
To use this model, click the Start Server button and initialize the server. Now, click the Setup Phase button, and tell the users to join. During this time, no code is actually executed, but the users can modify the plans for their units. Once players are satisfied with their initial plans for attack, unclick the Setup Phase button, and click the Start Game button. The model will then be running, with each players' units acting appropriately. If there is an error in the code for a player, that breed of the player's doesn't move, and the error message is passed to the player. The player can then correct the code and resubmit to the server. If a player wishes to pause the game (to allow more measured strategizing and programming), the user can set their "ready-to-pause" switch to true. If all players have this set to true, the game will pause. It will remain paused until ALL players set their switch to off.
To capture a base (either a white neutral base or a colored enemy base), simply attack it like you would any other unit. When a base is conquered, it becomes owner by a random one of the attack units.
Note: Ninjas can't attack bases.
The attack-any and defend-any commands make sure you don't accidentally attack your own team or heal an enemy team. The attack and defend commands don't take care of this for you.
Similarly, the attack-any and defend-any attempt to target intentionally. (They will target the nearest available appropriate enemy and will switch targets when necessary) The attack and defend commands make no such promises.
THINGS TO TRY
Try to develop more complicated strategies. You can be especially devious with the ninjas.
EXTENDING THE MODEL
You can extend this model in a myriad number of ways.
For example, you could:
Add new units.
Add new base types.
Rewrite the production model.
Modify the attack-any, defend-any, etc. commands.
Add new attack styles.
Implement anti-cheating checks.
Remove the checks from attack-any and defend-any that take care of inappropriate targeting (attacking your own team, healing the other team.)
Show damage on units.
NETLOGO FEATURES
Because of a lack of structures in NetLogo, a "players" breed was used to act as a struct. This breed is never shown or really interacted with; it's just used to store information relevant to each player. This is definitely a hack.
A lot of the __make-* code is duplicated; some kind of OOP inheritance here would've been neat.
Sometimes the hubnet-exit-message was getting fired more than once for the same client, so I had to write a little extra code to deal with that.
The carefully command is used to execute each units' code; therefore, if there is an error, we can convey it to the user instead of crashing.
RELATED MODELS
This is related to an unpublished model that implemented a HubNet version of the Prisoner's Dilemma. I believe it was written by Andrei Scheinkman.
CREDITS AND REFERENCES
This model was designed by Nate Nichols for MAM, Fall '05.
Comments and Questions
breed [ players player ] breed [ knights knight ] breed [ pirates pirate ] breed [ bases base] breed [ ninjas ninja ] players-own [name plans last-used last-error ready-to-pause] knights-own [owner plan health speed target targeted-by last-defended] pirates-own [owner plan health speed target targeted-by last-defended] ninjas-own [owner plan health speed target targeted-by last-defended] bases-own [owner plan health targeted-by] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;Functions beginning with __ are so named because otherwise they would sound like functions that would be called by players. ;;For purposes of game design and balance, these functions should not be called by players. to __make-knight ;;Base procedure hatch-knights 1 [ set owner [owner] of myself set color [color] of owner set speed knight-speed set health knight-attack-strength set target nobody set last-defended nobody set targeted-by [] set size 2 ] end to __make-pirate ;;Base procedure hatch-pirates 1 [ set owner [owner] of myself set color [color] of owner set speed pirate-speed set health pirate-health set target nobody set last-defended nobody set targeted-by [] set size 5 ] end to __make-ninja ;;Base procedure hatch-ninjas 1 [ set owner [owner] of myself set color [color] of owner set speed ninja-speed set health ninja-health set target nobody set last-defended nobody set targeted-by [] set size 2 ] end to __target [targ] ;;Unit procedure if target != nobody [ask target [set targeted-by remove myself targeted-by]] set target targ ask target [set targeted-by lput myself targeted-by] end to __attack ;;Unit procedure __move-towards-target if target != nobody [ ifelse breed = knights [ if distance target < knight-attack-range [ ask target [ set health health - knight-attack-strength ask turtles with [breed != players and color = [color] of myself] [ set health health + knight-heal-amount ] ] ] ] [ ifelse breed = pirates [ if distance target < pirate-attack-range [ask turtles with [breed != players and color != [color] of myself] [set health health - pirate-attack-strength]] ] [ if breed = ninjas [ if not member? target bases with [color != [color] of myself] [if distance target < ninja-attack-range [ask target [set health health - ninja-attack-strength]]] ] ] ] ] end to __move-towards-target ;;Unit procedure if target != nobody [ ifelse distance target > [size] of target [ set heading towards target + random (21) - 10 fd min list speed distance target ] [ setxy (xcor + (random-float .5) - .25) (ycor + (random-float .5) - .25) set heading towards target ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to startup hubnet-set-client-interface "COMPUTER" [] end to setup ca set-default-shape bases "house" set-default-shape knights "sword" set-default-shape pirates "crossbones" set-default-shape ninjas "ninja-star" create-bases base-count [ ;These are initially neutral bases set owner self setxy random 150 random 150 set color white set size 2 set health 10 set targeted-by [] ] end to-report load-file [filename] let ret "" file-open filename while [not file-at-end?] [ set ret word ret file-read-line set ret word ret " \\n " ] file-close report ret end to listen-clients while [ hubnet-message-waiting? ] [ hubnet-fetch-message ifelse hubnet-enter-message? [ create-new-student ] [ ifelse hubnet-exit-message? [ remove-student ] [ execute-command hubnet-message-tag ] ] ] end to create-new-student create-players 1 [ set name hubnet-message-source set plans (list "move-random" ) set plans lput "produce-knights" plans set plans lput "move-random" plans set plans lput "move-random" plans set color (count players - 1) * 10 + 5 set ready-to-pause false hubnet-send name "your-color" color set last-error "" hatch-bases 1 [ set owner myself setxy random 150 random 150 set color [color] of owner set size 2 set health 10 set targeted-by [] ] ht ] end to remove-student let leaving-player lookup-player hubnet-message-source if leaving-player != nobody [ ask leaving-player [ ask turtles with [breed != players and owner = myself] [die] die ] ] end to-report lookup-player [player-name] let player nobody ask players [ if name = player-name [set player self] ] report player end to-report atoi [brd] if brd = "knights" or brd = knights [report 0] if brd = "bases" or brd = bases [report 1] if brd = "pirates" or brd = pirates [report 2] if brd = "ninjas" or brd = ninjas [report 3] end to go listen-clients do-plans fix-turtles update-counts if not any? players with [not ready-to-pause] [ while [any? players with [ready-to-pause]] [ listen-clients wait 1 ] ] end to fix-turtles ask turtles with [breed != players and breed != bases and health < 0] [ if target != nobody [ ask target [ set targeted-by remove myself targeted-by ] ] foreach targeted-by [ask ? [set target nobody]] die ] ask bases with [health < 0] [ let killer one-of targeted-by hatch-bases 1 [ set owner [owner] of killer set color [color] of owner set size 2 set health base-health set targeted-by [] ] foreach targeted-by [ask ? [set target nobody]] die ] end to execute-command [comm] ifelse hubnet-message-tag = "comm" [ ask lookup-player hubnet-message-source [set plans replace-item atoi last-used plans hubnet-message] ] [ ifelse hubnet-message-tag = "ready-to-pause" [ ifelse hubnet-message [ ask lookup-player hubnet-message-source [set ready-to-pause true] ] [ ask lookup-player hubnet-message-source [set ready-to-pause false] ] ] [ let msg "" ask lookup-player hubnet-message-source [set msg item atoi hubnet-message-tag plans set last-used hubnet-message-tag] hubnet-send hubnet-message-source "comm" msg ] ] end to do-plans ask players [ carefully [ ask turtles with [breed != players and owner = myself] [ run item atoi breed [plans] of owner ] ] [ hubnet-send name "error-message" error-message ] ] end to update-counts ask players [ hubnet-send name "base-count" count bases with [owner = myself] hubnet-send name "knight-count" count knights with [owner = myself] hubnet-send name "pirate-count" count pirates with [owner = myself] hubnet-send name "ninja-count" count ninjas with [owner = myself] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;These functions are provided for players. to move-random rt random (30) - 15 fd speed end to produce-knights if random knight-produce-chance = 0 [__make-knight ] end to produce-pirates if random pirate-produce-chance = 0 [ __make-pirate] end to produce-ninjas if random ninja-produce-chance = 0 [__make-ninja] end to attack [new-target] __target new-target __attack end to attack-any [target-type] if target = nobody or not member? target target-type ;If old target isn't a member of new target, change target [ ifelse any? target-type with [ color != [color] of myself] [ __target min-one-of target-type with [ color != [color] of myself] [distance myself] ] [set target nobody] ] __attack end to defend [the-vic] ifelse length [targeted-by] of the-vic > 0 [attack one-of [targeted-by] of the-vic] [set target nobody] end to defend-any [vic-type] let defense-targets vic-type with [color = [color] of myself] if any? defense-targets [ attack-any turtles with [breed != players and breed != bases and color != [color] of myself and target != nobody and member? target defense-targets] ] end to ninja-hide if breed = ninjas [ht] end to ninja-show if breed = ninjas [st] end
There are 2 versions of this model.
Attached files
No files
This model does not have any ancestors.
This model does not have any descendants.