-
Notifications
You must be signed in to change notification settings - Fork 2
Network Protocol
In the current implementation, the server and client communicate using socket.io, but these messages could be implemented in a different communication mechanism. Message types below are identified by name, followed by a description of when they are sent, followed by example code to demonstrate the message structure.
-
join game
- sent to indicate that a client is watching a particular game and should receive updatessocket.emit("join game", 5);
-
alldata
- sent when the client wants the entire game state; gets aninitdata
message in responsesocket.emit("alldata", { gameId: 5 });
-
move
- sent to move a unit along a path; gets amoved
message broadcast in responsesocket.emit("move", { gameId: 5, path: [ { x: 3, y: 0 }, // the first coord is the position of the unit { x: 4, y: 0 }, { x: 5, y: 1 } // the final coord is an empty space or an enemy to be attacked ], attackIndex: 1 , // if the move is an attack, zero-indexed reference of which // attack should be used by the mover/attacker });
-
levelup
- must be sent by a player whose unit just finished a combat, if that unit now has XP greater than or equal tomaxXp
and that unit has anadvancesTo
array with at least two options. When those conditions are true, the player may not take any other action until this message is sent. (The client should make it clear this is necessary by showing a blocking advancement prompt.) The server will respond with aleveledup
broadcast message.socket.emit("levelup", { choiceNum: 1 // zero-indexed `advancesTo` index choice });
-
create
- sent to create a unit; gets acreated
message broadcast in responsesocket.emit("create", { gameId: 5, x: 5, y: 7, type: "orcish_archer" // unit type name });
-
endTurn
- ends the player's turn; answered with anewTurn
broadcast message and aplayerUpdate
to the new active playersocket.emit("endTurn", { gameId: 5 });
-
initdata
- response to aalldata
request; dump of all player-visible game infosocket.emit("initdata", { map: "map_file_name.map", // map file on the Web path http://hostname/data/maps/ timeOfDay: "morning", activeTeam: 1, // active player number player: { // data about your player team: 1, alliance: 1, gold: 72, username: "apsillers", faction: "orcs", // faction chosen from /data/factions advancingUnit: "5,1" // coords of unit who must resolve a branched level-up }, players: [ // list of all players in the game { username: "apsillers", team: 1, alliance: 1 }, { username: "anon123654", team: 2, alliance: 2, anonToken: "349503197" // used to play as an anon player, // only visible to Player #1 }, { username: "foobar", team: 3, alliance: 2 } ], alliances: { // mapping of player nums (key) to alliance (value) 1: 1, 2: 2, 3: 2 }, units: [ // array of all units visible to the player { type: "grunt", hp: 5, // no need to include max stats (maxHp, move) xp: 10, // since those stats are implied by the type maxHp: 30, // UNLESS some max stat of this specific unit differs team: 1, x: 2, y: 6, moveLeft: 3, attributes: ["resillient"], conditions: ["poisoned"] }, { ... }, ... ], villages: { "8,3": 1, // each key is the "x,y" location of a village "7,1": 2, // each value is the team number of village's owner "9,9": 0 // uncaptured villages have a value of 0 } });
-
moved
- sent to all players in response to amove
request; if the request is rejected (e.g., insufficient move points, path blocked by enemy), the update is sent back with an empty objectsocket.emit("moved", { gameId: 5, path: [ { x: 3, y: 0 }, // the first coord is the original position of the unit { x: 4, y: 0, hidden: true }, // "hidden" unit is on ambush terrain { hidden: true }, // opponents see unknown moves without x/y { x: 6, y: 0, hidden: true }, { x: 7, y: 0 } // if an attack, the position of the enemy unit is not included ], hide: false, // whether the unit is hidden at the end of the move unit: { ... }, // optional, used when the unit moving is not initially visible revealedUnits: [], // ambushing units revealed by the move moveCost: 4, // move-point cost of the move attack: true, // boolean indicating attack capture: true, // boolean indicating village capture combat: { // `combat` property present if the move is an attack offenseIndex: 1, // index of the attack used by offense // (from the list of the unit's attacks) defenseIndex: 1, // index of the attack used by defense offender: { x: 7, y: 0 }, // offender location defender: { x: 8, y: 0 }, // defender location xp: { offense: 12, // pre-level-up post-combat XP defense: 23, // tells the client when to level-up (if xp >= max) }, record: [ // record of combat rounds { event: "miss", // either "hit" or "miss" offense: true // true if attack committed by offender }, { event: "hit", offense: false, damage: 5 // "hit" events must include damage }, { event: "hit", offense: false, damage: 7, kill: true // true if this blow kills the unit } ] } });
-
leveledup
- broadcast to all players in response to alevelup
request, signifying that a unit has leveled up along a particular branching batch (indexed from zero, in order as listed in that unit'sadvancesTo
array). Only sent for units that level-up on the offensive with multiple choices in theiradvancesTo
array (all others level-up into their firstadvancesTo
choice)socket.emit("leveledup", { x: 5, y: 1, choiceNum: 1 // zero-indexed `advancesTo` index choice });
-
created
- sent to all players in response to acreate
request; if the request is rejected (e.g., insufficient gold, tile not in a commander-occupied castle), the message is sent back with an empty objectsocket.emit("created", { gameId: 5, x: 5, y: 7, type: "orcish_archer", // unit type name hp: 14, // unit properties... xp: 0, moveLeft: 5, ... });
-
newTurn
- sent to all players in response to anendTurn
request. The information included in theupdates
field for each player should be tailored to include information about units that the player can see (e.g., omit other players' ambush-hidden units)socket.emit("newTurn", { activeTeam: 2, updates: { // units that heal or suffer poison at the start of the turn "2,7": { // properties to update on the unit at (x,y) hp: 15, conditionChanges: { "poisoned": false } // `false` removes the condition }, "5,9": { ... } } });
-
playerUpdate
- used to update information about a player privately to a player (currently, just gold held by player)socket.emit("playerUpdate", { gold: 45 });