/** 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; }
// 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; }
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; }
// //////////////////////////////////////////////////////////////////////////// // 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; }
///////////////////////////////////////////////////////////////////////////////// // Returns a pointer to base object, given an id and optionally a player. BASE_OBJECT *IdToPointer(UDWORD id,UDWORD player) { DROID *pD; STRUCTURE *pS; FEATURE *pF; // droids. pD = IdToDroid(id, player); if (pD) { return (BASE_OBJECT*)pD; } // structures pS = IdToStruct(id,player); if(pS) { return (BASE_OBJECT*)pS; } // features pF = IdToFeature(id,player); if(pF) { return (BASE_OBJECT*)pF; } return NULL; }
/** 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; }
static QScriptValue js_groupAddDroid(QScriptContext *context, QScriptEngine *engine) { int groupId = context->argument(0).toInt32(); DROID_GROUP *psGroup = grpFind(groupId); QScriptValue droidVal = context->argument(1); int droidId = droidVal.property("id").toInt32(); int droidPlayer = droidVal.property("player").toInt32(); DROID *psDroid = IdToDroid(droidId, droidPlayer); SCRIPT_ASSERT(context, psGroup, "Invalid group index %d", groupId); SCRIPT_ASSERT(context, psDroid, "Invalid droid index %d", droidId); psGroup->add(psDroid); return QScriptValue(); }
static QScriptValue js_orderDroidLoc(QScriptContext *context, QScriptEngine *) { QScriptValue droidVal = context->argument(0); int id = droidVal.property("id").toInt32(); int player = droidVal.property("player").toInt32(); QScriptValue orderVal = context->argument(1); int x = context->argument(2).toInt32(); int y = context->argument(3).toInt32(); DROID_ORDER order = (DROID_ORDER)orderVal.toInt32(); DROID *psDroid = IdToDroid(id, player); SCRIPT_ASSERT(context, psDroid, "Droid id %d not found belonging to player %d", id, player); SCRIPT_ASSERT(context, worldOnMap(x, y), "Outside map bounds (%d, %d)", x, y); orderDroidLoc(psDroid, order, x, y, ModeQueue); return QScriptValue(); }
// //////////////////////////////////////////////////////////////////////////// // process droid order static BASE_OBJECT *processDroidTarget(OBJECT_TYPE desttype, uint32_t destid) { // Target is a location if (destid == 0 && desttype == 0) { return NULL; } // Target is an object else { BASE_OBJECT *psObj = NULL; DROID *pD; switch (desttype) { case OBJ_DROID: if (IdToDroid(destid, ANYPLAYER, &pD)) { psObj = (BASE_OBJECT*)pD; } break; case OBJ_STRUCTURE: psObj = (BASE_OBJECT*)IdToStruct(destid,ANYPLAYER); break; case OBJ_FEATURE: psObj = (BASE_OBJECT*)IdToFeature(destid,ANYPLAYER); break; // We should not get this! case OBJ_PROJECTILE: debug(LOG_ERROR, "ProcessDroidOrder: order specified destination as a bullet. what am i to do??"); break; default: debug(LOG_ERROR, "ProcessDroidOrder: unknown object type"); break; } // If we did not find anything, return if (!psObj) // failed to find it; { syncDebug("Target missing"); return TargetMissing; // Can't return NULL, since then the order would still be attempted. } return psObj; } }
// recvGiftDroid() // We received a droid gift from another player. // NOTICE: the packet is already set-up for decoding via recvGift() // // \param from :player that sent us the droid // \param to :player that should be getting the droid static void recvGiftDroids(uint8_t from, uint8_t to, uint32_t droidID) { DROID *psDroid; if (IdToDroid(droidID, from, &psDroid)) { giftSingleDroid(psDroid, to); if (to == selectedPlayer) { CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives you a %s"), getPlayerName(from), psDroid->aName)); } } else { debug(LOG_ERROR, "Bad droid id %u, from %u to %u", droidID, from, to); } }
// //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine bool recvDestroyDroid(NETQUEUE queue) { DROID *psDroid; NETbeginDecode(queue, GAME_DEBUG_REMOVE_DROID); { uint32_t id; // Retrieve the droid NETuint32_t(&id); psDroid = IdToDroid(id, ANYPLAYER); if (!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 (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to remove droid for player %u.", NetPlay.players[queue.index].position); return false; } // 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, gameTime - deltaGameTime + 1); // deltaGameTime is actually 0 here, since we're between updates. However, the value of gameTime - deltaGameTime + 1 will not change when we start the next tick. turnOffMultiMsg(false); } else { debug(LOG_DEATH, "droid %d is confirmed dead by player %d.", psDroid->id, queue.index); } return true; }
// //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine bool recvDestroyDroid(NETQUEUE queue) { DROID* psDroid; NETbeginDecode(queue, GAME_DEBUG_REMOVE_DROID); { uint32_t id; // Retrieve the droid NETuint32_t(&id); psDroid = IdToDroid(id, ANYPLAYER); if (!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 (!getDebugMappingStatus()) { debug(LOG_WARNING, "Failed to remove droid for player %u.", NetPlay.players[queue.index].position); return false; } // 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, gameTime); turnOffMultiMsg(false); } else { debug(LOG_DEATH, "droid %d is confirmed dead by player %d.", psDroid->id, queue.index); } return true; }
BOOL recvDemolishFinished(NETMSG *m) { STRUCTURE *psStruct; UDWORD s,d; DROID *psDroid; NetGet(m,0,s); NetGet(m,4,d); psStruct = IdToStruct(s,ANYPLAYER); IdToDroid(d,ANYPLAYER,&psDroid); if(psStruct) { removeStruct( psStruct, TRUE ); // demolish it. if(psDroid && psDroid->psTarStats) { psDroid->psTarStats = NULL; // update droid if reqd. } } return TRUE; }
static QScriptValue js_label(QScriptContext *context, QScriptEngine *engine) { QString label = context->argument(0).toString(); QScriptValue ret = engine->newObject(); if (labels.contains(label)) { labeltype p = labels.value(label); if (p.type == AREA || p.type == POSITION) { ret.setProperty("x", map_coord(p.p1.x), QScriptValue::ReadOnly); ret.setProperty("y", map_coord(p.p1.y), QScriptValue::ReadOnly); } if (p.type == AREA) { ret.setProperty("x2", map_coord(p.p2.x), QScriptValue::ReadOnly); ret.setProperty("xy", map_coord(p.p2.y), QScriptValue::ReadOnly); } else if (p.type == OBJ_DROID) { DROID *psDroid = IdToDroid(p.id, p.player); if (psDroid) ret = convDroid(psDroid, engine); } else if (p.type == OBJ_STRUCTURE) { STRUCTURE *psStruct = IdToStruct(p.id, p.player); if (psStruct) ret = convStructure(psStruct, engine); } else if (p.type == OBJ_FEATURE) { FEATURE *psFeature = IdToFeature(p.id, p.player); if (psFeature) ret = convFeature(psFeature, engine); } } else debug(LOG_ERROR, "label %s not found!", label.toUtf8().constData()); return ret; }
// //////////////////////////////////////////////////////////////////////////// // receive droid information form other players. BOOL recvDroidInfo(NETQUEUE queue) { NETbeginDecode(queue, GAME_DROIDINFO); { QueuedDroidInfo info; memset(&info, 0x00, sizeof(info)); NETQueuedDroidInfo(&info); STRUCTURE_STATS *psStats = NULL; if (info.order == DORDER_BUILD || info.order == DORDER_LINEBUILD) { // Find structure target for (unsigned typeIndex = 0; typeIndex < numStructureStats; typeIndex++) { if (asStructureStats[typeIndex].ref == info.structRef) { psStats = asStructureStats + typeIndex; break; } } } if (info.subType) { syncDebug("Order=%s,%d(%d)", getDroidOrderName(info.order), info.destId, info.destType); } else { syncDebug("Order=%s,(%d,%d)", getDroidOrderName(info.order), info.x, info.y); } DROID_ORDER_DATA sOrder; memset(&sOrder, 0x00, sizeof(sOrder)); sOrder.order = info.order; sOrder.x = info.x; sOrder.y = info.y; sOrder.x2 = info.x2; sOrder.y2 = info.y2; sOrder.direction = info.direction; sOrder.psObj = processDroidTarget(info.destType, info.destId); sOrder.psStats = (BASE_STATS *)psStats; uint32_t num = 0; NETuint32_t(&num); for (unsigned n = 0; n < num; ++n) { // Get the next droid ID which is being given this order. uint32_t deltaDroidId = 0; NETuint32_t(&deltaDroidId); info.droidId += deltaDroidId; DROID *psDroid = NULL; if (!IdToDroid(info.droidId, ANYPLAYER, &psDroid)) { debug(LOG_NEVER, "Packet from %d refers to non-existent droid %u, [%s : p%d]", queue.index, info.droidId, isHumanPlayer(info.player) ? "Human" : "AI", info.player); syncDebug("Droid %d missing", info.droidId); continue; // Can't find the droid, so skip this droid. } CHECK_DROID(psDroid); syncDebugDroid(psDroid, '<'); psDroid->waitingForOwnReceiveDroidInfoMessage = false; /* * If the current order not is a command order and we are not a * commander yet are in the commander group remove us from it. */ if (hasCommander(psDroid)) { grpLeave(psDroid->psGroup, psDroid); } if (sOrder.psObj != TargetMissing) // Only do order if the target didn't die. { orderDroidBase(psDroid, &sOrder); } syncDebugDroid(psDroid, '>'); CHECK_DROID(psDroid); } } NETend(); return true; }
/** Receive info about a droid that is being unloaded from a transporter * * \sa sendDroidEmbark(),recvDroidEmbark(),sendDroidDisEmbark() */ BOOL recvDroidDisEmbark(NETQUEUE queue) { DROID *psFoundDroid = NULL, *psTransporterDroid = NULL; DROID *psCheckDroid = NULL; NETbeginDecode(queue, GAME_DROIDDISEMBARK); { uint8_t player; uint32_t droidID; uint32_t transporterID; Position pos; NETuint8_t(&player); NETuint32_t(&droidID); NETuint32_t(&transporterID); NETPosition(&pos); NETend(); // find the transporter first if (!IdToDroid(transporterID, player, &psTransporterDroid)) { // Possible it already died? (sync error?) debug(LOG_WARNING, "player's %d transport droid %d wasn't found?", player, transporterID); 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; } // remove it from the transporter grpLeave(psFoundDroid->psGroup, psFoundDroid); // and add it back to the bloody droid list addDroid(psFoundDroid, apsDroidLists); // Add it back into the world at the x/y droidSetPrecisePosition(psFoundDroid, pos); if (!droidOnMap(psFoundDroid)) { debug(LOG_ERROR, "droid %d disembarked was NOT on map?", psFoundDroid->id); return false; } updateDroidOrientation(psFoundDroid); // Initialise the movement data initDroidMovement(psFoundDroid); } return true; }
// //////////////////////////////////////////////////////////////////////////// // put down a base plate and start droid building it! BOOL recvBuildStarted() { STRUCTURE_STATS *psStats; DROID *psDroid; UDWORD actionX,actionY; unsigned int typeIndex; uint8_t player; uint16_t x, y, z; int32_t order; uint32_t structRef, structId, targetId,droidID; NETbeginDecode(NET_BUILD); NETuint8_t(&player); NETuint32_t(&structRef); NETuint16_t(&x); NETuint16_t(&y); NETuint32_t(&droidID); NETuint32_t(&structId); NETint32_t(&order); NETuint32_t(&targetId); NETuint16_t(&z); NETend(); // Find structure target for (typeIndex = 0; typeIndex < numStructureStats && asStructureStats[typeIndex].ref != structRef; typeIndex++); psStats = &asStructureStats[typeIndex]; if (IdToDroid(droidID, player, &psDroid)) { // Tell the droid to go to where it needs to in order to build the struct if (getDroidDestination((BASE_STATS *) psStats, x, y, &actionX, &actionY)) { psDroid->order = order; if (psDroid->order == DORDER_LINEBUILD) { psDroid->order = DORDER_BUILD; } psDroid->orderX = x; psDroid->orderY = y; psDroid->psTarStats = (BASE_STATS *) psStats; if (targetId) { setDroidTarget(psDroid, IdToPointer(targetId, ANYPLAYER)); } else { setDroidTarget(psDroid, NULL); } if (IsStatExpansionModule(psStats)) { setUpBuildModule(psDroid); } else { droidStartBuild(psDroid); psDroid->action = DACTION_BUILD; } } // Sync IDs if (psDroid->psTarget) { ((STRUCTURE *) psDroid->psTarget)->id = structId; } } return true; }
// //////////////////////////////////////////////////////////////////////////// // receive a check and update the local world state accordingly BOOL recvDroidCheck(NETQUEUE queue) { uint8_t count; int i; uint32_t synchTime; NETbeginDecode(queue, GAME_CHECK_DROID); // Get the number of droids to expect NETuint8_t(&count); NETuint32_t(&synchTime); // Get game time. for (i = 0; i < count; i++) { DROID * pD; PACKAGED_CHECK pc, pc2; Position precPos; NETPACKAGED_CHECK(&pc); // Find the droid in question if (!IdToDroid(pc.droidID, pc.player, &pD)) { NETlogEntry("Recvd Unknown droid info. val=player", SYNC_FLAG, pc.player); debug(LOG_SYNC, "Received checking info for an unknown (as yet) droid. player:%d ref:%d", pc.player, pc.droidID); continue; } syncDebugDroid(pD, '<'); if (pD->gameCheckDroid == NULL) { debug(LOG_SYNC, "We got a droid %u synch, but we couldn't find the droid!", pc.droidID); continue; // Can't synch, since we didn't save data to be able to calculate a delta. } pc2 = *(PACKAGED_CHECK *)pD->gameCheckDroid; // pc2 should be declared here, as const. if (pc2.gameTime != synchTime + MIN_DELAY_BETWEEN_DROID_SYNCHS) { debug(LOG_SYNC, "We got a droid %u synch, but we didn't choose the same droid to synch.", pc.droidID); ((PACKAGED_CHECK *)pD->gameCheckDroid)->gameTime = synchTime + MIN_DELAY_BETWEEN_DROID_SYNCHS; // Get droid synch time back in synch. continue; // Can't synch, since we didn't save data to be able to calculate a delta. } #define MERGECOPY(x, y, z) if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z" to %"z".", pc.droidID, x, pc.y); x = pc.y; } #define MERGEDELTA(x, y, z) if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z" to %"z".", pc.droidID, x, x + pc.y - pc2.y); x += pc.y - pc2.y; } // player not synched here... precPos = droidGetPrecisePosition(pD); MERGEDELTA(precPos.x, pos.x, "d"); MERGEDELTA(precPos.y, pos.y, "d"); MERGEDELTA(precPos.z, pos.z, "d"); droidSetPrecisePosition(pD, precPos); MERGEDELTA(pD->rot.direction, rot.direction, "d"); MERGEDELTA(pD->rot.pitch, rot.pitch, "d"); MERGEDELTA(pD->rot.roll, rot.roll, "d"); MERGEDELTA(pD->body, body, "u"); if (pD->body > pD->originalBody) { pD->body = pD->originalBody; debug(LOG_SYNC, "Droid %u body was too high after synch, reducing to %u.", pc.droidID, pD->body); } MERGEDELTA(pD->experience, experience, "u"); if (pc.pos.x != pc2.pos.x || pc.pos.y != pc2.pos.y) { // snap droid(if on ground) to terrain level at x,y. if ((asPropulsionStats + pD->asBits[COMP_PROPULSION].nStat)->propulsionType != PROPULSION_TYPE_LIFT) // if not airborne. { pD->pos.z = map_Height(pD->pos.x, pD->pos.y); } } // Doesn't cover all cases, but at least doesn't actively break stuff randomly. switch (pc.order) { case DORDER_MOVE: if (pc.order != pc2.order || pc.orderX != pc2.orderX || pc.orderY != pc2.orderY) { debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%d, %d).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.orderX, pc.orderY); // reroute the droid. orderDroidLoc(pD, pc.order, pc.orderX, pc.orderY, ModeImmediate); } break; case DORDER_ATTACK: if (pc.order != pc2.order || pc.targetID != pc2.targetID) { BASE_OBJECT *obj = IdToPointer(pc.targetID, ANYPLAYER); if (obj != NULL) { debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%u).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.targetID); // remote droid is attacking, not here tho! orderDroidObj(pD, pc.order, IdToPointer(pc.targetID, ANYPLAYER), ModeImmediate); } else { debug(LOG_SYNC, "Droid %u out of synch, would change order from %s to %s(%u), but can't find target.", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.targetID); } } break; case DORDER_NONE: case DORDER_GUARD: if (pc.order != pc2.order) { DROID_ORDER_DATA sOrder; memset(&sOrder, 0, sizeof(DROID_ORDER_DATA)); sOrder.order = pc.order; debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s.", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order)); turnOffMultiMsg(true); moveStopDroid(pD); orderDroidBase(pD, &sOrder); turnOffMultiMsg(false); } break; default: break; // Don't know what to do, but at least won't be actively breaking anything. } MERGECOPY(pD->secondaryOrder, secondaryOrder, "u"); // The old code set this after changing orders, so doing that in case. #undef MERGECOPY #undef MERGEDELTA syncDebugDroid(pD, '>'); // ...and repeat! } NETend(); return true; }
// //////////////////////////////////////////////////////////////////////////// // receive droid information form other players. bool recvDroidInfo(NETQUEUE queue) { NETbeginDecode(queue, GAME_DROIDINFO); { QueuedDroidInfo info; memset(&info, 0x00, sizeof(info)); NETQueuedDroidInfo(&info); STRUCTURE_STATS *psStats = NULL; if (info.subType == LocOrder && (info.order == DORDER_BUILD || info.order == DORDER_LINEBUILD)) { // Find structure target for (unsigned typeIndex = 0; typeIndex < numStructureStats; typeIndex++) { if (asStructureStats[typeIndex].ref == info.structRef) { psStats = asStructureStats + typeIndex; break; } } } switch (info.subType) { case ObjOrder: syncDebug("Order=%s,%d(%d)", getDroidOrderName(info.order), info.destId, info.destType); break; case LocOrder: syncDebug("Order=%s,(%d,%d)", getDroidOrderName(info.order), info.pos.x, info.pos.y); break; case SecondaryOrder: syncDebug("SecondaryOrder=%d,%08X", (int)info.secOrder, (int)info.secState); break; } DROID_ORDER_DATA sOrder = infoToOrderData(info, psStats); uint32_t num = 0; NETuint32_t(&num); for (unsigned n = 0; n < num; ++n) { // Get the next droid ID which is being given this order. uint32_t deltaDroidId = 0; NETuint32_t(&deltaDroidId); info.droidId += deltaDroidId; DROID *psDroid = IdToDroid(info.droidId, info.player); if (!psDroid) { debug(LOG_NEVER, "Packet from %d refers to non-existent droid %u, [%s : p%d]", queue.index, info.droidId, isHumanPlayer(info.player) ? "Human" : "AI", info.player); syncDebug("Droid %d missing", info.droidId); continue; // Can't find the droid, so skip this droid. } CHECK_DROID(psDroid); syncDebugDroid(psDroid, '<'); switch (info.subType) { case ObjOrder: case LocOrder: /* * If the current order not is a command order and we are not a * commander yet are in the commander group remove us from it. */ if (hasCommander(psDroid)) { psDroid->psGroup->remove(psDroid); } if (sOrder.psObj != TargetMissing) // Only do order if the target didn't die. { if (!info.add) { orderDroidListEraseRange(psDroid, 0, psDroid->listSize + 1); // Clear all non-pending orders, plus the first pending order (which is probably the order we just received). orderDroidBase(psDroid, &sOrder); // Execute the order immediately (even if in the middle of another order. } else { orderDroidAdd(psDroid, &sOrder); // Add the order to the (non-pending) list. Will probably overwrite the corresponding pending order, assuming all pending orders were written to the list. } } break; case SecondaryOrder: // Set the droids secondary order turnOffMultiMsg(true); secondarySetState(psDroid, info.secOrder, info.secState); turnOffMultiMsg(false); break; } syncDebugDroid(psDroid, '>'); CHECK_DROID(psDroid); } } NETend(); return true; }
// //////////////////////////////////////////////////////////////////////////// // put down a base plate and start droid building it! BOOL recvBuildStarted(NETMSG *pMsg) { //UDWORD targetId,order,droidId,structId,x,z,y,structStat,player; UDWORD targetId,order,droidId,structId,structStat; UWORD x,z,y,player; STRUCTURE_STATS *psStats; DROID *psDroid; UDWORD typeindex,actionX,actionY; player = pMsg->body[0]; // decode message. NetGet(pMsg,1,structStat); NetGet(pMsg,5,x); NetGet(pMsg,7,y); NetGet(pMsg,11,droidId); NetGet(pMsg,15,structId); order = pMsg->body[19]; NetGet(pMsg,20,targetId); NetGet(pMsg,24,z); for(typeindex=0; // find structure target (typeindex<numStructureStats ) && (asStructureStats[typeindex].ref != structStat); typeindex++); psStats = &asStructureStats[typeindex]; if(IdToDroid(droidId,player, &psDroid)) { if (getDroidDestination( (BASE_STATS *)psStats ,x,y, &actionX,&actionY)) { psDroid->order = order; if(psDroid->order == DORDER_LINEBUILD) { psDroid->order = DORDER_BUILD; } psDroid->orderX = x; psDroid->orderY = y; psDroid->psTarStats = (BASE_STATS *) psStats; if(targetId) { psDroid->psTarget = IdToPointer(targetId,ANYPLAYER); } else { psDroid->psTarget = 0; } if (IsStatExpansionModule(psStats)) { setUpBuildModule(psDroid); } else { droidStartBuild(psDroid); psDroid->action = DACTION_BUILD; } } if (psDroid->psTarget) //sync id's { ((STRUCTURE*)psDroid->psTarget)->id = structId; } } // order droid to start building it. return TRUE; }