Skip to content

Network Protocol

Andrew Sillers edited this page Aug 31, 2015 · 9 revisions

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.

Client requests

  • join game - sent to indicate that a client is watching a particular game and should receive updates

      socket.emit("join game", 5);
    
  • alldata - sent when the client wants the entire game state; gets an initdata message in response

      socket.emit("alldata", { gameId: 5 });
    
  • move - sent to move a unit along a path; gets a moved message broadcast in response

      socket.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 to maxXp and that unit has an advancesTo 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 a leveledup broadcast message.

      socket.emit("levelup", {
          choiceNum: 1    // zero-indexed `advancesTo` index choice
      });
    
  • create - sent to create a unit; gets a created message broadcast in response

      socket.emit("create", {
          gameId: 5,
          x: 5,
          y: 7,
          type: "orcish_archer"  // unit type name
      });
    
  • endTurn - ends the player's turn; answered with a newTurn broadcast message and a playerUpdate to the new active player

      socket.emit("endTurn", { gameId: 5 });
    

Server updates

  • initdata - response to a alldata request; dump of all player-visible game info

      socket.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 a move request; if the request is rejected (e.g., insufficient move points, path blocked by enemy), the update is sent back with an empty object

      socket.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 a levelup request, signifying that a unit has leveled up along a particular branching batch (indexed from zero, in order as listed in that unit's advancesTo array). Only sent for units that level-up on the offensive with multiple choices in their advancesTo array (all others level-up into their first advancesTo choice)

      socket.emit("leveledup", {
          x: 5,
          y: 1,
          choiceNum: 1    // zero-indexed `advancesTo` index choice
      });
    
  • created - sent to all players in response to a create 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 object

      socket.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 an endTurn request. The information included in the updates 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
      });
    
Clone this wiki locally