void recvMultiPlayerFeature(NETQUEUE queue) { uint32_t ref = 0xff, x = 0, y = 0, id = 0; unsigned int i; NETbeginDecode(queue, GAME_DEBUG_ADD_FEATURE); { NETuint32_t(&ref); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&id); } NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to add feature for player %u.", NetPlay.players[queue.index].position); return; } // Find the feature stats list that contains the feature type we want to build for (i = 0; i < numFeatureStats; ++i) { // If we found the correct feature type if (asFeatureStats[i].ref == ref) { // Create a feature of the specified type at the given location FEATURE *result = buildFeature(&asFeatureStats[i], x, y, false); result->id = id; break; } } }
void recvPlayerGameTime(NETQUEUE queue) { uint32_t latencyTicks = 0; uint32_t checkTime = 0; uint32_t checkCrc = 0; NETbeginDecode(queue, GAME_GAME_TIME); NETuint32_t(&latencyTicks); NETuint32_t(&checkTime); NETuint32_tLarge(&checkCrc); NETuint16_t(&wantedLatencies[queue.index]); NETend(); gameQueueTime[queue.index] = checkTime + latencyTicks * GAME_TICKS_PER_UPDATE; // gameTime when future messages shall be processed. gameQueueCheckTime[queue.index] = checkTime; gameQueueCheckCrc[queue.index] = checkCrc; if (!checkDebugSync(checkTime, checkCrc)) { crcError = true; if (NetPlay.players[queue.index].allocated) { NETsetPlayerConnectionStatus(CONNECTIONSTATUS_DESYNC, queue.index); } } if (updateReadyTime == 0 && checkPlayerGameTime(NET_ALL_PLAYERS)) { updateReadyTime = wzGetTicks(); // This is the time we were able to tick. } }
// //////////////////////////////////////////////////////////////////////////// // Set Player's stats // send stats to all players when bLocal is false BOOL setMultiStats(SDWORD player, PLAYERSTATS plStats, BOOL bLocal) { uint32_t playerIndex = (uint32_t)player; if (playerIndex >= MAX_PLAYERS) { return true; } // First copy over the data into our local array memcpy(&playerStats[playerIndex], &plStats, sizeof(plStats)); if (!bLocal) { // Now send it to all other players NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_STATS); // Send the ID of the player's stats we're updating NETuint32_t(&playerIndex); // Send over the actual stats NETuint32_t(&playerStats[playerIndex].played); NETuint32_t(&playerStats[playerIndex].wins); NETuint32_t(&playerStats[playerIndex].losses); NETuint32_t(&playerStats[playerIndex].totalKills); NETuint32_t(&playerStats[playerIndex].totalScore); NETuint32_t(&playerStats[playerIndex].recentKills); NETuint32_t(&playerStats[playerIndex].recentScore); NETuint32_t(&playerStats[playerIndex].killsToAdd); NETuint32_t(&playerStats[playerIndex].scoreToAdd); NETend(); } return true; }
void recvMultiStats(NETQUEUE queue) { uint32_t playerIndex; NETbeginDecode(queue, NET_PLAYER_STATS); // Retrieve the ID number of the player for which we need to // update the stats NETuint32_t(&playerIndex); if (playerIndex >= MAX_PLAYERS) { return; } // we don't what to update ourselves, we already know our score (FIXME: rewrite setMultiStats()) if (!myResponsibility(playerIndex)) { // Retrieve the actual stats NETuint32_t(&playerStats[playerIndex].played); NETuint32_t(&playerStats[playerIndex].wins); NETuint32_t(&playerStats[playerIndex].losses); NETuint32_t(&playerStats[playerIndex].totalKills); NETuint32_t(&playerStats[playerIndex].totalScore); NETuint32_t(&playerStats[playerIndex].recentKills); NETuint32_t(&playerStats[playerIndex].recentScore); NETuint32_t(&playerStats[playerIndex].killsToAdd); NETuint32_t(&playerStats[playerIndex].scoreToAdd); } NETend(); }
BOOL recvDemolishFinished(NETQUEUE queue) { STRUCTURE *psStruct; DROID *psDroid; uint32_t structID, droidID; NETbeginDecode(queue, GAME_DEMOLISH); NETuint32_t(&structID); NETuint32_t(&droidID); NETend(); psStruct = IdToStruct(structID, ANYPLAYER); if (!IdToDroid(droidID, ANYPLAYER, &psDroid)) { debug(LOG_ERROR, "recvDemolishFinished: Packet with bad droid ID received. Discarding!"); return false; } if (psStruct) { // Demolish it // Should never get here, if in synch. removeStruct(psStruct, true); if (psDroid && psDroid->psTarStats) { // Update droid if reqd psDroid->psTarStats = NULL; } } return true; }
// recv lassat info on the receiving end. BOOL recvLasSat(NETQUEUE queue) { BASE_OBJECT *psObj; UBYTE player,targetplayer; STRUCTURE *psStruct; uint32_t id,targetid; // TODO Add some kind of checking, so that things don't get lasatted by bunkers. NETbeginDecode(queue, GAME_LASSAT); NETuint8_t(&player); NETuint32_t(&id); NETuint32_t(&targetid); NETuint8_t(&targetplayer); NETend(); psStruct = IdToStruct (id, player); psObj = IdToPointer(targetid, targetplayer); if (psStruct && psObj) { // Give enemy no quarter, unleash the lasat proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0); psStruct->asWeaps[0].lastFired = gameTime; // Play 5 second countdown message audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z); } return true; }
// //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // New research stuff, so you can see what others are up to! // inform others that I'm researching this. bool sendResearchStatus(STRUCTURE *psBuilding, uint32_t index, uint8_t player, bool bStart) { if (!myResponsibility(player) || gameTime < 5) { return true; } NETbeginEncode(NETgameQueue(selectedPlayer), GAME_RESEARCHSTATUS); NETuint8_t(&player); NETbool(&bStart); // If we know the building researching it then send its ID if (psBuilding) { NETuint32_t(&psBuilding->id); } else { uint32_t zero = 0; NETuint32_t(&zero); } // Finally the topic in question NETuint32_t(&index); NETend(); // Tell UI to remove from the list of available research. MakeResearchStartedPending(&asPlayerResList[player][index]); return true; }
// //////////////////////////////////////////////////////////////////////////// // Send a new Droid to the other players bool SendDroid(DROID_TEMPLATE *pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrdersP) { if (!bMultiMessages) { return true; } ASSERT_OR_RETURN(false, x != 0 && y != 0, "SendDroid: Invalid droid coordinates"); ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player); // Dont send other droids during campaign setup if (ingame.localJoiningInProgress) { return true; } // Only send the droid if we are responsible if (!myResponsibility(player)) { // Don't build if we are not responsible return false; } debug(LOG_SYNC, "Droid sent with id of %u", id); NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEBUG_ADD_DROID); { Position pos(x, y, 0); bool haveInitialOrders = initialOrdersP != NULL; int32_t droidType = pTemplate->droidType; NETuint8_t(&player); NETuint32_t(&id); NETPosition(&pos); NETqstring(pTemplate->name); NETint32_t(&droidType); NETuint8_t(&pTemplate->asParts[COMP_BODY]); NETuint8_t(&pTemplate->asParts[COMP_BRAIN]); NETuint8_t(&pTemplate->asParts[COMP_PROPULSION]); NETuint8_t(&pTemplate->asParts[COMP_REPAIRUNIT]); NETuint8_t(&pTemplate->asParts[COMP_ECM]); NETuint8_t(&pTemplate->asParts[COMP_SENSOR]); NETuint8_t(&pTemplate->asParts[COMP_CONSTRUCT]); NETint8_t(&pTemplate->numWeaps); for (int i = 0; i < pTemplate->numWeaps; i++) { NETuint8_t(&pTemplate->asWeaps[i]); } NETbool(&haveInitialOrders); if (haveInitialOrders) { INITIAL_DROID_ORDERS initialOrders = *initialOrdersP; NETuint32_t(&initialOrders.secondaryOrder); NETint32_t(&initialOrders.moveToX); NETint32_t(&initialOrders.moveToY); NETuint32_t(&initialOrders.factoryId); // For making scripts happy. } } debug(LOG_LIFE, "===> sending Droid from %u id of %u ", player, id); return NETend(); }
// recv lassat info on the receiving end. BOOL recvLasSat() { BASE_OBJECT *psObj; UBYTE player,targetplayer; STRUCTURE *psStruct; uint32_t id,targetid; NETbeginDecode(NET_LASSAT); NETuint8_t(&player); NETuint32_t(&id); NETuint32_t(&targetid); NETuint8_t(&targetplayer); NETend(); psStruct = IdToStruct (id, player); psObj = IdToPointer(targetid, targetplayer); if (psStruct && psObj) { // Give enemy no quarter, unleash the lasat proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0); // Play 5 second countdown message audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z); } return true; }
// send complete game info set! void sendOptions() { bool dummy = true; unsigned int i; if (!NetPlay.isHost || !bHosted) // Only host should act, and only if the game hasn't started yet. { ASSERT(false, "Host only routine detected for client or not hosting yet!"); return; } NETbeginEncode(NETbroadcastQueue(), NET_OPTIONS); // First send information about the game NETuint8_t(&game.type); NETstring(game.map, 128); NETuint8_t(&game.maxPlayers); NETstring(game.name, 128); NETbool(&dummy); NETuint32_t(&game.power); NETuint8_t(&game.base); NETuint8_t(&game.alliance); NETbool(&game.scavengers); for (i = 0; i < MAX_PLAYERS; i++) { NETuint8_t(&game.skDiff[i]); } // Send the list of who is still joining for (i = 0; i < MAX_PLAYERS; i++) { NETbool(&ingame.JoiningInProgress[i]); } // Same goes for the alliances for (i = 0; i < MAX_PLAYERS; i++) { unsigned int j; for (j = 0; j < MAX_PLAYERS; j++) { NETuint8_t(&alliances[i][j]); } } // Send the number of structure limits to expect NETuint32_t(&ingame.numStructureLimits); debug(LOG_NET, "(Host) Structure limits to process on client is %u", ingame.numStructureLimits); // Send the structures changed for (i = 0; i < ingame.numStructureLimits; i++) { NETuint32_t(&ingame.pStructureLimits[i].id); NETuint32_t(&ingame.pStructureLimits[i].limit); } updateLimitFlags(); NETuint8_t(&ingame.flags); NETend(); }
/** Receive droid and transporter loading information * * \sa sendDroidEmbark(),sendDroidDisEmbark(),recvDroidDisEmbark() */ BOOL recvDroidEmbark(NETQUEUE queue) { DROID* psDroid; DROID* psTransporterDroid; BOOL bDroidRemoved; NETbeginDecode(queue, GAME_DROIDEMBARK); { uint8_t player; uint32_t droidID; uint32_t transporterID; NETuint8_t(&player); NETuint32_t(&droidID); NETuint32_t(&transporterID); // we have to find the droid on our (local) list first. if (!IdToDroid(droidID, player, &psDroid)) { NETend(); // Possible it already died? (sync error?) debug(LOG_WARNING, "player's %d droid %d wasn't found?", player,droidID); return false; } if (!IdToDroid(transporterID, player, &psTransporterDroid)) { NETend(); // Possible it already died? (sync error?) debug(LOG_WARNING, "player's %d transport droid %d wasn't found?", player,transporterID); return false; } if (psDroid == NULL) { // how can this happen? return true; } // Take it out of the world without destroying it (just removes it from the droid list) bDroidRemoved = droidRemove(psDroid, apsDroidLists); // Init the order for when disembark psDroid->order = DORDER_NONE; setDroidTarget(psDroid, NULL); psDroid->psTarStats = NULL; if (bDroidRemoved) { // and now we need to add it to their transporter group! grpJoin(psTransporterDroid->psGroup, psDroid); } else { // possible sync error? debug(LOG_WARNING, "Eh? Where did unit %d go? Couldn't load droid onto transporter.", droidID); } } NETend(); return true; }
// Actually send the droid info. void sendQueuedDroidInfo() { // Sort queued orders, to group the same order to multiple droids. std::sort(queuedOrders.begin(), queuedOrders.end()); std::vector<QueuedDroidInfo>::iterator eqBegin, eqEnd; for (eqBegin = queuedOrders.begin(); eqBegin != queuedOrders.end(); eqBegin = eqEnd) { // Find end of range of orders which differ only by the droid ID. for (eqEnd = eqBegin + 1; eqEnd != queuedOrders.end() && eqEnd->orderCompare(*eqBegin) == 0; ++eqEnd) {} NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROIDINFO); NETQueuedDroidInfo(&*eqBegin); uint32_t num = eqEnd - eqBegin; NETuint32_t(&num); uint32_t prevDroidId = 0; for (unsigned n = 0; n < num; ++n) { uint32_t droidId = (eqBegin + n)->droidId; // Encode deltas between droid IDs, since the deltas are smaller than the actual droid IDs, and will encode to less bytes on average. uint32_t deltaDroidId = droidId - prevDroidId; NETuint32_t(&deltaDroidId); prevDroidId = droidId; } NETend(); } // Sent the orders. Don't send them again. queuedOrders.clear(); }
void recvMultiPlayerFeature(NETQUEUE queue) { FEATURE_TYPE subType = FEAT_TREE; // Dummy initialisation. uint32_t x, y, id; unsigned int i; NETbeginDecode(queue, GAME_FEATURES); { NETenum(&subType); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&id); } NETend(); // Find the feature stats list that contains the feature type we want to build for (i = 0; i < numFeatureStats; ++i) { // If we found the correct feature type if (asFeatureStats[i].subType == subType) { // Create a feature of the specified type at the given location FEATURE *result = buildFeature(&asFeatureStats[i], x, y, false); result->id = id; break; } } }
// //////////////////////////////////////////////////////////////////////////// // demolish message. BOOL SendDemolishFinished(STRUCTURE *psStruct, DROID *psDroid) { NETbeginEncode(NET_DEMOLISH, NET_ALL_PLAYERS); // Send what is being demolish and who is doing it NETuint32_t(&psStruct->id); NETuint32_t(&psDroid->id); return NETend(); }
// //////////////////////////////////////////////////////////////////////////// // demolish message. BOOL SendDemolishFinished(STRUCTURE *psStruct, DROID *psDroid) { NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEMOLISH); // Send what is being demolish and who is doing it NETuint32_t(&psStruct->id); NETuint32_t(&psDroid->id); return NETend(); }
// /////////////////////////////////////////////////////////////// // receive splattered artifacts void recvMultiPlayerRandomArtifacts(NETQUEUE queue) { int count, i; uint8_t quantity, player; uint32_t tx,ty; uint32_t ref; FEATURE_TYPE type = FEAT_TREE; // Dummy initialisation. FEATURE *pF; NETbeginDecode(queue, GAME_ARTIFACTS); NETuint8_t(&quantity); NETenum(&type); debug(LOG_FEATURE, "receiving %u artifact(s) type: (%s)", quantity, feature_names[type]); for (i = 0; i < numFeatureStats && asFeatureStats[i].subType != type; i++) {} for (count = 0; count < quantity; count++) { MAPTILE *psTile; NETuint32_t(&tx); NETuint32_t(&ty); NETuint32_t(&ref); NETuint8_t(&player); if (tx == INVALID_XY) { continue; } else if (!tileOnMap(tx, ty)) { debug(LOG_ERROR, "Bad tile coordinates (%u,%u)", tx, ty); continue; } psTile = mapTile(tx, ty); if (!psTile || psTile->psObject != NULL) { debug(LOG_ERROR, "Already something at (%u,%u)!", tx, ty); continue; } pF = buildFeature((asFeatureStats + i), world_coord(tx), world_coord(ty), false); if (pF) { pF->id = ref; pF->player = player; syncDebugFeature(pF, '+'); } else { debug(LOG_ERROR, "Couldn't build feature %u for player %u ?", ref, player); } } NETend(); }
/** Sends a build order for the given feature type to all players * \param subType the type of feature to build * \param x,y the coordinates to place the feature at */ void sendMultiPlayerFeature(FEATURE_TYPE subType, uint32_t x, uint32_t y, uint32_t id) { NETbeginEncode(NET_FEATURES, NET_ALL_PLAYERS); { NETenum(&subType); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&id); } NETend(); }
/** Sends a build order for the given feature type to all players * \param subType the type of feature to build * \param x,y the coordinates to place the feature at */ void sendMultiPlayerFeature(uint32_t ref, uint32_t x, uint32_t y, uint32_t id) { NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEBUG_ADD_FEATURE); { NETuint32_t(&ref); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&id); } NETend(); }
BOOL sendLasSat(UBYTE player, STRUCTURE *psStruct, BASE_OBJECT *psObj) { NETbeginEncode(NETgameQueue(selectedPlayer), GAME_LASSAT); NETuint8_t(&player); NETuint32_t(&psStruct->id); NETuint32_t(&psObj->id); // Target NETuint8_t(&psObj->player); // Target player return NETend(); }
/** Sends a build order for the given feature type to all players * \param subType the type of feature to build * \param x,y the coordinates to place the feature at */ void sendMultiPlayerFeature(FEATURE_TYPE subType, uint32_t x, uint32_t y, uint32_t id) { NETbeginEncode(NETgameQueue(selectedPlayer), GAME_FEATURES); { NETenum(&subType); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&id); } NETend(); }
BOOL sendLasSat(UBYTE player, STRUCTURE *psStruct, BASE_OBJECT *psObj) { NETbeginEncode(NET_LASSAT, NET_ALL_PLAYERS); NETuint8_t(&player); NETuint32_t(&psStruct->id); NETuint32_t(&psObj->id); // Target NETuint8_t(&psObj->player); // Target player return NETend(); }
//AI multiplayer message, send from a certain player index to another player index bool sendAIMessage(char *pStr, UDWORD player, UDWORD to) { UDWORD sendPlayer; //check if this is one of the local players, don't need net send then if (to == selectedPlayer || myResponsibility(to)) //(the only) human on this machine or AI on this machine { triggerEventChat(player, to, pStr); //Just show "him" the message displayAIMessage(pStr, player, to); //Received a console message from a player callback //store and call later //------------------------------------------------- if (!msgStackPush(CALL_AI_MSG,player,to,pStr,-1,-1,NULL)) { debug(LOG_ERROR, "sendAIMessage() - msgStackPush - stack failed"); return false; } } else //not a local player (use multiplayer mode) { if (!ingame.localOptionsReceived) { return true; } //find machine that is hosting this human or AI sendPlayer = whosResponsible(to); if (sendPlayer >= MAX_PLAYERS) { debug(LOG_ERROR, "sendAIMessage() - sendPlayer >= MAX_PLAYERS"); return false; } if (!isHumanPlayer(sendPlayer)) //NETsend can't send to non-humans { debug(LOG_ERROR, "sendAIMessage() - player is not human."); return false; } //send to the player who is hosting 'to' player (might be himself if human and not AI) NETbeginEncode(NETnetQueue(sendPlayer), NET_AITEXTMSG); NETuint32_t(&player); //save the actual sender //save the actual player that is to get this msg on the source machine (source can host many AIs) NETuint32_t(&to); //save the actual receiver (might not be the same as the one we are actually sending to, in case of AIs) NETstring(pStr, MAX_CONSOLE_STRING_LENGTH); // copy message in. NETend(); } return true; }
/** Receive info about a droid that is being unloaded from a transporter */ bool recvDroidDisEmbark(NETQUEUE queue) { DROID *psFoundDroid = NULL, *psTransporterDroid = NULL; DROID *psCheckDroid = NULL; NETbeginDecode(queue, GAME_DROIDDISEMBARK); { uint32_t player; uint32_t droidID; uint32_t transporterID; NETuint32_t(&player); NETuint32_t(&droidID); NETuint32_t(&transporterID); NETend(); // find the transporter first psTransporterDroid = IdToDroid(transporterID, player); if (!psTransporterDroid) { // Possible it already died? (sync error?) debug(LOG_WARNING, "player's %d transport droid %d wasn't found?", player, transporterID); return false; } if (!canGiveOrdersFor(queue.index, psTransporterDroid->player)) { return false; } // we need to find the droid *in* the transporter psCheckDroid = psTransporterDroid ->psGroup->psList; while (psCheckDroid) { // is this the one we want? if (psCheckDroid->id == droidID) { psFoundDroid = psCheckDroid; break; } // not found, so check next one in *group* psCheckDroid = psCheckDroid->psGrpNext; } // don't continue if we couldn't find it. if (!psFoundDroid) { // I don't think this could ever be possible...but debug(LOG_ERROR, "Couldn't find droid %d to disembark from player %d's transporter?", droidID, player); return false; } transporterRemoveDroid(psTransporterDroid, psFoundDroid, ModeImmediate); } return true; }
// send complete game info set! void sendOptions() { unsigned int i; NETbeginEncode(NETbroadcastQueue(), NET_OPTIONS); // First send information about the game NETuint8_t(&game.type); NETstring(game.map, 128); NETuint8_t(&game.maxPlayers); NETstring(game.name, 128); NETbool(&game.fog); NETuint32_t(&game.power); NETuint8_t(&game.base); NETuint8_t(&game.alliance); NETbool(&game.scavengers); for (i = 0; i < MAX_PLAYERS; i++) { NETuint8_t(&game.skDiff[i]); } // Send the list of who is still joining for (i = 0; i < MAX_PLAYERS; i++) { NETbool(&ingame.JoiningInProgress[i]); } // Same goes for the alliances for (i = 0; i < MAX_PLAYERS; i++) { unsigned int j; for (j = 0; j < MAX_PLAYERS; j++) { NETuint8_t(&alliances[i][j]); } } // Send the number of structure limits to expect NETuint32_t(&ingame.numStructureLimits); debug(LOG_NET, "(Host) Structure limits to process on client is %u", ingame.numStructureLimits); // Send the structures changed for (i = 0; i < ingame.numStructureLimits; i++) { NETuint32_t(&ingame.pStructureLimits[i].id); NETuint32_t(&ingame.pStructureLimits[i].limit); } updateLimitFlags(); NETuint8_t(&ingame.flags); NETend(); }
// //////////////////////////////////////////////////////////////////////////// // add an artifact on destruction if required. void technologyGiveAway(const STRUCTURE *pS) { int i; uint8_t count = 1; uint32_t x, y; FEATURE *pF = NULL; FEATURE_TYPE type = FEAT_GEN_ARTE; // If a fully built factory (or with modules under construction) which is our responsibility got destroyed if (pS->pStructureType->type == REF_FACTORY && (pS->status == SS_BUILT || pS->currentBuildPts >= pS->body) && myResponsibility(pS->player)) { x = map_coord(pS->pos.x); y = map_coord(pS->pos.y); // Pick a tile to place the artifact if (!pickATileGen(&x, &y, LOOK_FOR_EMPTY_TILE, zonedPAT)) { ASSERT(false, "technologyGiveAway: Unable to find a free location"); } // Get the feature offset for(i = 0; i < numFeatureStats && asFeatureStats[i].subType != FEAT_GEN_ARTE; i++); // 'Build' the artifact pF = buildFeature((asFeatureStats + i), world_coord(x), world_coord(y), false); if (pF) { pF->player = pS->player; } NETbeginEncode(NET_ARTIFACTS, NET_ALL_PLAYERS); { /* Make sure that we don't have to violate the constness of pS. * Since the nettype functions aren't const correct when sending */ uint8_t player = pS->player; NETuint8_t(&count); NETenum(&type); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&pF->id); NETuint8_t(&player); } NETend(); } return; }
// recv lassat info on the receiving end. bool recvLasSat(NETQUEUE queue) { BASE_OBJECT *psObj; UBYTE player, targetplayer; STRUCTURE *psStruct; uint32_t id, targetid; NETbeginDecode(queue, GAME_LASSAT); NETuint8_t(&player); NETuint32_t(&id); NETuint32_t(&targetid); NETuint8_t(&targetplayer); NETend(); psStruct = IdToStruct(id, player); psObj = IdToPointer(targetid, targetplayer); if (psStruct && !canGiveOrdersFor(queue.index, psStruct->player)) { syncDebug("Wrong player."); return false; } if (psStruct && psObj && psStruct->pStructureType->psWeapStat[0]->weaponSubClass == WSC_LAS_SAT) { // Lassats have just one weapon unsigned firePause = weaponFirePause(&asWeaponStats[psStruct->asWeaps[0].nStat], player); unsigned damLevel = PERCENT(psStruct->body, structureBody(psStruct)); if (damLevel < HEAVY_DAMAGE_LEVEL) { firePause += firePause; } if (isHumanPlayer(player) && gameTime - psStruct->asWeaps[0].lastFired <= firePause) { /* Too soon to fire again */ return true ^ false; // Return value meaningless and ignored. } // Give enemy no quarter, unleash the lasat proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0); psStruct->asWeaps[0].lastFired = gameTime; psStruct->asWeaps[0].ammo = 1; // abducting this field for keeping track of triggers // Play 5 second countdown message audio_QueueTrackPos(ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z); } return true; }
// //////////////////////////////////////////////////////////////////////////// // Set Player's stats // send stats to all players when bLocal is false bool setMultiStats(uint32_t playerIndex, PLAYERSTATS plStats, bool bLocal) { if (playerIndex >= MAX_PLAYERS) { return true; } // First copy over the data into our local array playerStats[playerIndex] = plStats; if (!bLocal) { // Now send it to all other players NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_STATS); // Send the ID of the player's stats we're updating NETuint32_t(&playerIndex); // Send over the actual stats NETuint32_t(&playerStats[playerIndex].played); NETuint32_t(&playerStats[playerIndex].wins); NETuint32_t(&playerStats[playerIndex].losses); NETuint32_t(&playerStats[playerIndex].totalKills); NETuint32_t(&playerStats[playerIndex].totalScore); NETuint32_t(&playerStats[playerIndex].recentKills); NETuint32_t(&playerStats[playerIndex].recentScore); NETend(); } return true; }
// //////////////////////////////////////////////////////////////////////////// // INFORM others that a building has been completed. BOOL SendBuildFinished(STRUCTURE *psStruct) { uint8_t player = psStruct->player; ASSERT( player < MAX_PLAYERS, "invalid player %u", player); NETbeginEncode(NETgameQueue(selectedPlayer), GAME_BUILDFINISHED); NETuint32_t(&psStruct->id); // ID of building // Along with enough info to build it (if needed) NETuint32_t(&psStruct->pStructureType->ref); NETPosition(&psStruct->pos); NETuint8_t(&player); return NETend(); }
// //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine BOOL recvDestroyDroid(NETQUEUE queue) { DROID* psDroid; NETbeginDecode(queue, GAME_DROIDDEST); { uint32_t id; // Retrieve the droid NETuint32_t(&id); if (!IdToDroid(id, ANYPLAYER, &psDroid)) { debug(LOG_DEATH, "droid %d on request from player %d can't be found? Must be dead already?", id, queue.index ); return false; } } NETend(); // If the droid has not died on our machine yet, destroy it if(!psDroid->died) { turnOffMultiMsg(true); debug(LOG_DEATH, "Killing droid %d on request from player %d - huh?", psDroid->id, queue.index); destroyDroid(psDroid); turnOffMultiMsg(false); } else { debug(LOG_DEATH, "droid %d is confirmed dead by player %d.", psDroid->id, queue.index); } return true; }
// recv BOOL recvDroidSecondary(NETQUEUE queue) { DROID* psDroid; SECONDARY_ORDER sec = DSO_ATTACK_RANGE; SECONDARY_STATE state = DSS_NONE; NETbeginDecode(queue, GAME_SECONDARY); { uint8_t player; uint32_t droid; NETuint8_t(&player); NETuint32_t(&droid); NETenum(&sec); NETenum(&state); // If we can not find the droid should we not ask for it? if (!IdToDroid(droid, player, &psDroid)) { NETend(); return false; } } NETend(); // Set the droids secondary order turnOffMultiMsg(true); secondarySetState(psDroid, sec, state); turnOffMultiMsg(false); return true; }