///////////////////////////////////////////////////////////////////////////////// // 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; }
// 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; }
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() { 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; }
// //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. bool recvDestroyStructure(NETQUEUE queue) { uint32_t structID; STRUCTURE *psStruct; NETbeginDecode(queue, GAME_DEBUG_REMOVE_STRUCTURE); NETuint32_t(&structID); NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to remove structure for player %u.", NetPlay.players[queue.index].position); return false; } // Struct to destory psStruct = IdToStruct(structID, ANYPLAYER); if (psStruct) { turnOffMultiMsg(true); // Remove the struct from remote players machine destroyStruct(psStruct, 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); // NOTE: I do not think this should be here! technologyGiveAway(psStruct); } return true; }
// recv lassat info on the receiving end. BOOL recvLasSat(NETMSG *pMsg) { BASE_OBJECT *psObj; UBYTE player,targetplayer; STRUCTURE *psStruct; UDWORD id,tid; NetGet(pMsg,0,player); NetGet(pMsg,1,id); NetGet(pMsg,5,tid); NetGet(pMsg,9,targetplayer); psStruct = IdToStruct (id ,player); psObj = IdToPointer(tid,targetplayer); if(psStruct && psObj) { proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->x, psObj->y, psObj->z, psObj, TRUE); //play 5 second countdown message audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->x, psObj->y, psObj->z ); } return TRUE; }
static QScriptValue js_structureIdle(QScriptContext *context, QScriptEngine *) { QScriptValue structVal = context->argument(0); int id = structVal.property("id").toInt32(); int player = structVal.property("player").toInt32(); STRUCTURE *psStruct = IdToStruct(id, player); SCRIPT_ASSERT(context, psStruct, "No such structure id %d belonging to player %d", id, player); return QScriptValue(structureIdle(psStruct)); }
// 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; }
// //////////////////////////////////////////////////////////////////////////// // 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; } }
// NOTICE: the packet is already set-up for decoding via recvGift() static void recvGiftStruct(uint8_t from, uint8_t to, uint32_t structID) { STRUCTURE *psStruct = IdToStruct(structID, from); if (psStruct) { syncDebugStructure(psStruct, '<'); giftSingleStructure(psStruct, to, false); syncDebugStructure(psStruct, '>'); if (to == selectedPlayer) { CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives you a %s"), getPlayerName(from), objInfo(psStruct))); } } else { debug(LOG_ERROR, "Bad structure id %u, from %u to %u", structID, from, to); } }
/* Build a droid template in the specified factory */ static QScriptValue js_buildDroid(QScriptContext *context, QScriptEngine *) { QScriptValue structVal = context->argument(1); int id = structVal.property("id").toInt32(); int player = structVal.property("player").toInt32(); QScriptValue templName = context->argument(0); DROID_TEMPLATE *psTemplate = getTemplateFromTranslatedNameNoPlayer(templName.toString().toUtf8().constData()); STRUCTURE *psStruct = IdToStruct(id, player); SCRIPT_ASSERT(context, psStruct != NULL, "No factory object found for id %d, player %d", id, player); SCRIPT_ASSERT(context, psTemplate != NULL, "No template object found for %s sent to %s", templName.toString().toUtf8().constData(), objInfo(psStruct)); SCRIPT_ASSERT(context, (psStruct->pStructureType->type == REF_FACTORY || psStruct->pStructureType->type == REF_CYBORG_FACTORY || psStruct->pStructureType->type == REF_VTOL_FACTORY), "Structure %s is not a factory", objInfo(psStruct)); SCRIPT_ASSERT(context, validTemplateForFactory(psTemplate, psStruct), "Invalid template - %s for factory - %s", psTemplate->aName, psStruct->pStructureType->pName); return QScriptValue(structSetManufacture(psStruct, psTemplate, ModeQueue)); }
// //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. BOOL recvDestroyStructure(NETMSG * m) { UDWORD s; STRUCTURE *psStr; NetGet(m,0,s); // struct to destory psStr = IdToStruct(s,ANYPLAYER); if (psStr) { turnOffMultiMsg(TRUE); destroyStruct(psStr); // remove the struct from remote players machine. turnOffMultiMsg(FALSE); technologyGiveAway(psStr); return (TRUE); } 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; }
// //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. BOOL recvDestroyStructure(NETQUEUE queue) { uint32_t structID; STRUCTURE *psStruct; NETbeginDecode(queue, GAME_STRUCTDEST); NETuint32_t(&structID); NETend(); // Struct to destory psStruct = IdToStruct(structID,ANYPLAYER); if (psStruct) { turnOffMultiMsg(true); // Remove the struct from remote players machine destroyStruct(psStruct); turnOffMultiMsg(false); // NOTE: I do not think this should be here! technologyGiveAway(psStruct); } return true; }
// //////////////////////////////////////////////////////////////////////////// // receive droid creation information from other players bool recvDroid(NETQUEUE queue) { DROID_TEMPLATE t, *pT = &t; DROID *psDroid; uint8_t player; uint32_t id; Position pos; bool haveInitialOrders; INITIAL_DROID_ORDERS initialOrders; NETbeginDecode(queue, GAME_DEBUG_ADD_DROID); { int32_t droidType; NETuint8_t(&player); NETuint32_t(&id); NETPosition(&pos); NETqstring(pT->name); pT->id = pT->name; NETint32_t(&droidType); NETuint8_t(&pT->asParts[COMP_BODY]); NETuint8_t(&pT->asParts[COMP_BRAIN]); NETuint8_t(&pT->asParts[COMP_PROPULSION]); NETuint8_t(&pT->asParts[COMP_REPAIRUNIT]); NETuint8_t(&pT->asParts[COMP_ECM]); NETuint8_t(&pT->asParts[COMP_SENSOR]); NETuint8_t(&pT->asParts[COMP_CONSTRUCT]); NETint8_t(&pT->numWeaps); for (int i = 0; i < pT->numWeaps; i++) { NETuint8_t(&pT->asWeaps[i]); } NETbool(&haveInitialOrders); if (haveInitialOrders) { NETuint32_t(&initialOrders.secondaryOrder); NETint32_t(&initialOrders.moveToX); NETint32_t(&initialOrders.moveToY); NETuint32_t(&initialOrders.factoryId); // For making scripts happy. } pT->droidType = (DROID_TYPE)droidType; } NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to add droid for player %u.", NetPlay.players[queue.index].position); return false; } ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player); debug(LOG_LIFE, "<=== getting Droid from %u id of %u ", player, id); if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight)) { debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y, queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); return false; } // Create that droid on this machine. psDroid = reallyBuildDroid(pT, pos, player, false); // If we were able to build the droid set it up if (psDroid) { psDroid->id = id; addDroid(psDroid, apsDroidLists); if (haveInitialOrders) { psDroid->secondaryOrder = initialOrders.secondaryOrder; psDroid->secondaryOrderPending = psDroid->secondaryOrder; orderDroidLoc(psDroid, DORDER_MOVE, initialOrders.moveToX, initialOrders.moveToY, ModeImmediate); cbNewDroid(IdToStruct(initialOrders.factoryId, ANYPLAYER), psDroid); } syncDebugDroid(psDroid, '+'); } else { debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); #ifdef DEBUG CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync")); #endif return false; } return true; }
void recvStructureInfo(NETQUEUE queue) { uint8_t player = 0; uint32_t structId = 0; uint32_t templateId = 0; uint8_t structureInfo; STRUCTURE *psStruct; DROID_TEMPLATE *psTempl = NULL; NETbeginDecode(queue, GAME_STRUCTUREINFO); NETuint8_t(&player); NETuint32_t(&structId); NETuint8_t(&structureInfo); if (structureInfo == STRUCTUREINFO_MANUFACTURE) { NETuint32_t(&templateId); if (templateId != 0) { // For autogames, where we want the AI to take us over, our templates are not setup... so let's use any AI's templates. if (!NetPlay.players[player].autoGame) { psTempl = IdToTemplate(templateId, player); } else { psTempl = IdToTemplate(templateId, ANYPLAYER); } if (psTempl == NULL) { debug(LOG_SYNC, "Synch error, don't have tempate id %u, so can't change production of factory %u!", templateId, structId); } } } NETend(); psStruct = IdToStruct(structId, player); syncDebug("player%d,structId%u%c,structureInfo%u,templateId%u%c", player, structId, psStruct == NULL ? '^' : '*', structureInfo, templateId, psTempl == NULL ? '^' : '*'); if (psStruct == NULL) { debug(LOG_SYNC, "Couldn't find structure %u to change production.", structId); return; } if (!canGiveOrdersFor(queue.index, psStruct->player)) { syncDebug("Wrong player."); return; } CHECK_STRUCTURE(psStruct); if (StructIsFactory(psStruct)) { popStatusPending(psStruct->pFunctionality->factory); } else if (psStruct->pStructureType->type == REF_RESEARCH) { popStatusPending(psStruct->pFunctionality->researchFacility); } syncDebugStructure(psStruct, '<'); switch (structureInfo) { case STRUCTUREINFO_MANUFACTURE: structSetManufacture(psStruct, psTempl, ModeImmediate); break; case STRUCTUREINFO_CANCELPRODUCTION: cancelProduction(psStruct, ModeImmediate, false); break; case STRUCTUREINFO_HOLDPRODUCTION: holdProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASEPRODUCTION: releaseProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_HOLDRESEARCH: holdResearch(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASERESEARCH: releaseResearch(psStruct, ModeImmediate); break; default: debug(LOG_ERROR, "Invalid structureInfo %d", structureInfo); } syncDebugStructure(psStruct, '>'); CHECK_STRUCTURE(psStruct); }
// //////////////////////////////////////////////////////////////////////////// // receive droid creation information from other players BOOL recvDroid(NETQUEUE queue) { DROID_TEMPLATE* pT; DROID* psDroid; uint8_t player; uint32_t id; Position pos; uint32_t templateID; BOOL haveInitialOrders; INITIAL_DROID_ORDERS initialOrders; NETbeginDecode(queue, GAME_DROID); { NETuint8_t(&player); NETuint32_t(&id); NETPosition(&pos); NETuint32_t(&templateID); NETbool(&haveInitialOrders); if (haveInitialOrders) { NETuint32_t(&initialOrders.secondaryOrder); NETint32_t(&initialOrders.moveToX); NETint32_t(&initialOrders.moveToY); NETuint32_t(&initialOrders.factoryId); // For making scripts happy. } pT = IdToTemplate(templateID, player); } NETend(); ASSERT( player < MAX_PLAYERS, "invalid player %u", player); debug(LOG_LIFE, "<=== getting Droid from %u id of %u ",player,id); if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight)) { debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y, queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); return false; } // If we can not find the template ask for the entire droid instead if (!pT) { debug(LOG_ERROR, "Packet from %d refers to non-existent template %u, [%s : p%d]", queue.index, templateID, isHumanPlayer(player) ? "Human" : "AI", player); return false; } // Create that droid on this machine. psDroid = reallyBuildDroid(pT, pos.x, pos.y, player, false); // If we were able to build the droid set it up if (psDroid) { psDroid->id = id; addDroid(psDroid, apsDroidLists); if (haveInitialOrders) { psDroid->secondaryOrder = initialOrders.secondaryOrder; orderDroidLoc(psDroid, DORDER_MOVE, initialOrders.moveToX, initialOrders.moveToY, ModeImmediate); cbNewDroid(IdToStruct(initialOrders.factoryId, ANYPLAYER), psDroid); } } else { debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); #ifdef DEBUG CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync")); #endif return false; } return true; }
// //////////////////////////////////////////////////////////////////////////// BOOL recvBuildFinished(NETQUEUE queue) { uint32_t structId; STRUCTURE *psStruct; Position pos; uint32_t type,typeindex; uint8_t player; NETbeginDecode(queue, GAME_BUILDFINISHED); NETuint32_t(&structId); // get the struct id. NETuint32_t(&type); // Kind of building. NETPosition(&pos); // pos NETuint8_t(&player); NETend(); ASSERT( player < MAX_PLAYERS, "invalid player %u", player); psStruct = IdToStruct(structId,ANYPLAYER); if (psStruct) { // make it complete. psStruct->currentBuildPts = psStruct->pStructureType->buildPoints+1; if (psStruct->status != SS_BUILT) { debug(LOG_SYNC, "Synch error, structure %u was not complete, and should have been.", structId); psStruct->status = SS_BUILT; buildingComplete(psStruct); } debug(LOG_SYNC, "Created normal building %u for player %u", psStruct->id, player); return true; } // The building wasn't started, so we'll have to just plonk it down in the map. // Find the structures stats for (typeindex=0; // Find structure target (typeindex<numStructureStats ) && (asStructureStats[typeindex].ref != type); typeindex++); // Check for similar buildings, to avoid overlaps if (TileHasStructure(mapTile(map_coord(pos.x), map_coord(pos.y)))) { // Get the current structure psStruct = getTileStructure(map_coord(pos.x), map_coord(pos.y)); if (asStructureStats[typeindex].type == psStruct->pStructureType->type) { // Correct type, correct location, just rename the id's to sync it.. (urgh) psStruct->id = structId; psStruct->status = SS_BUILT; buildingComplete(psStruct); debug(LOG_SYNC, "Created modified building %u for player %u", psStruct->id, player); #if defined (DEBUG) NETlogEntry("structure id modified", SYNC_FLAG, player); #endif return true; } } // Build the structure psStruct = buildStructure(&(asStructureStats[typeindex]), pos.x, pos.y, player, true); if (psStruct) { psStruct->id = structId; psStruct->status = SS_BUILT; buildingComplete(psStruct); debug(LOG_SYNC, "Huge synch error, forced to create building %u for player %u", psStruct->id, player); #if defined (DEBUG) NETlogEntry("had to plonk down a building", SYNC_FLAG, player); #endif } else { debug(LOG_SYNC, "Gigantic synch error, unable to create building for player %u", player); NETlogEntry("had to plonk down a building, BUT FAILED!", SYNC_FLAG, player); } return false; }
void recvStructureInfo(NETQUEUE queue) { uint8_t player = 0; uint32_t structId = 0; uint32_t templateId = 0; uint8_t structureInfo; STRUCTURE * psStruct; DROID_TEMPLATE *psTempl = NULL; NETbeginDecode(queue, GAME_STRUCTUREINFO); NETuint8_t(&player); NETuint32_t(&structId); NETuint8_t(&structureInfo); if (structureInfo == STRUCTUREINFO_MANUFACTURE) { NETuint32_t(&templateId); if (templateId != 0) { psTempl = IdToTemplate(templateId, player); if (psTempl == NULL) { debug(LOG_SYNC, "Synch error, don't have tempate id %u, so can't change production of factory %u!", templateId, structId); } } } NETend(); psStruct = IdToStruct(structId, player); syncDebug("player%d,structId%u%c,structureInfo%u,templateId%u%c", player, structId, psStruct == NULL? '^' : '*', structureInfo, templateId, psTempl == NULL? '^' : '*'); if (psStruct == NULL) { debug(LOG_SYNC, "Couldn't find structure %u to change production.", structId); return; } CHECK_STRUCTURE(psStruct); if (StructIsFactory(psStruct)) { if (psStruct->pFunctionality->factory.pendingCount == 0) { ++psStruct->pFunctionality->factory.pendingCount; } if (--psStruct->pFunctionality->factory.pendingCount == 0) { // Subject is now synchronised, remove pending. psStruct->pFunctionality->factory.psSubjectPending = NULL; psStruct->pFunctionality->factory.statusPending = FACTORY_NOTHING_PENDING; } } syncDebugStructure(psStruct, '<'); switch (structureInfo) { case STRUCTUREINFO_MANUFACTURE: structSetManufacture(psStruct, psTempl, ModeImmediate); break; case STRUCTUREINFO_CANCELPRODUCTION: cancelProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_HOLDPRODUCTION: holdProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASEPRODUCTION: releaseProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_HOLDRESEARCH: holdResearch(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASERESEARCH: releaseResearch(psStruct, ModeImmediate); break; default: debug(LOG_ERROR, "Invalid structureInfo %d", structureInfo); } syncDebugStructure(psStruct, '>'); CHECK_STRUCTURE(psStruct); }
// //////////////////////////////////////////////////////////////////////////// BOOL recvBuildFinished() { uint32_t structId; STRUCTURE *psStruct; int32_t x,y,z; uint32_t type,typeindex; uint8_t player; uint32_t power; NETbeginDecode(NET_BUILDFINISHED); NETuint32_t(&power); // get the player's power level NETuint32_t(&structId); // get the struct id. NETuint32_t(&type); // Kind of building. NETint32_t(&x); // x pos NETint32_t(&y); // y pos NETint32_t(&z); // z pos NETuint8_t(&player); NETend(); ASSERT( player < MAX_PLAYERS, "invalid player %u", player); psStruct = IdToStruct(structId,ANYPLAYER); setPower( (uint32_t)player, power); // we sync the power level as well if (psStruct) { // make it complete. psStruct->currentBuildPts = psStruct->pStructureType->buildPoints+1; if (psStruct->status != SS_BUILT) { psStruct->status = SS_BUILT; buildingComplete(psStruct); } debug(LOG_SYNC, "Created normal building %u for player %u", psStruct->id, player); return true; } // The building wasn't started, so we'll have to just plonk it down in the map. // Find the structures stats for (typeindex=0; // Find structure target (typeindex<numStructureStats ) && (asStructureStats[typeindex].ref != type); typeindex++); // Check for similar buildings, to avoid overlaps if (TileHasStructure(mapTile(map_coord(x), map_coord(y)))) { // Get the current structure psStruct = getTileStructure(map_coord(x), map_coord(y)); if (asStructureStats[typeindex].type == psStruct->pStructureType->type) { // Correct type, correct location, just rename the id's to sync it.. (urgh) psStruct->id = structId; psStruct->status = SS_BUILT; buildingComplete(psStruct); debug(LOG_SYNC, "Created modified building %u for player %u", psStruct->id, player); #if defined (DEBUG) NETlogEntry("structure id modified", SYNC_FLAG, player); #endif return true; } } // Build the structure psStruct = buildStructure(&(asStructureStats[typeindex]), x, y, player, true); if (psStruct) { psStruct->id = structId; psStruct->status = SS_BUILT; buildingComplete(psStruct); debug(LOG_SYNC, "Forced to create building %u for player %u", psStruct->id, player); #if defined (DEBUG) NETlogEntry("had to plonk down a building" ,SYNC_FLAG, player); #endif } else { debug(LOG_SYNC, "Unable to create building for player %u", player); NETlogEntry("had to plonk down a building, BUT FAILED!" , SYNC_FLAG, player); } return false; }
// receive checking info about a structure and update local world state BOOL recvStructureCheck(NETQUEUE queue) { uint32_t synchTime; STRUCTURE *pS; BOOL hasCapacity = true; int j; Rotation rot; uint8_t player, ourCapacity; uint32_t body; uint32_t ref; uint32_t type; NETbeginDecode(queue, GAME_CHECK_STRUCT); NETuint8_t(&player); NETuint32_t(&synchTime); NETuint32_t(&ref); NETuint32_t(&body); NETuint32_t(&type); NETRotation(&rot); if (player >= MAX_PLAYERS) { debug(LOG_ERROR, "Bad GAME_CHECK_STRUCT received!"); NETend(); return false; } if (structureCheckLastSent != synchTime) { debug(LOG_ERROR, "We got a structure synch at the wrong time."); } if (ref != structureCheckLastId[player]) { debug(LOG_ERROR, "We got a structure %u synch, but had chosen %u instead.", ref, structureCheckLastId[player]); NETend(); return false; } // If the structure exists our job is easy pS = IdToStruct(ref, player); if (pS) { syncDebugStructure(pS, '<'); if (pS->pStructureType->type != structureCheckLastType[player] || type != structureCheckLastType[player]) { debug(LOG_ERROR, "GAME_CHECK_STRUCT received, wrong structure type!"); NETend(); return false; } // Check its finished if (pS->status != SS_BUILT) { pS->rot = rot; pS->id = ref; pS->status = SS_BUILT; buildingComplete(pS); } // If the structure has a capacity switch (pS->pStructureType->type) { case REF_RESEARCH: ourCapacity = ((RESEARCH_FACILITY *) pS->pFunctionality)->capacity; j = researchModuleStat; break; case REF_FACTORY: case REF_VTOL_FACTORY: ourCapacity = ((FACTORY *) pS->pFunctionality)->capacity; j = factoryModuleStat; break; case REF_POWER_GEN: ourCapacity = ((POWER_GEN *) pS->pFunctionality)->capacity; j = powerModuleStat; break; default: hasCapacity = false; break; } // So long as the struct has a capacity fetch it from the packet if (hasCapacity) { uint8_t actualCapacity = 0; NETuint8_t(&actualCapacity); // If our capacity is different upgrade ourself for (; ourCapacity < actualCapacity; ourCapacity++) { debug(LOG_SYNC, "Structure %u out of synch, adding module.", ref); buildStructure(&asStructureStats[j], pS->pos.x, pS->pos.y, pS->player, false); // Check it is finished if (pS && pS->status != SS_BUILT) { pS->id = ref; pS->status = SS_BUILT; buildingComplete(pS); } } } #define MERGEDELTA(x, y, ya, z) if (y != ya) { debug(LOG_SYNC, "Structure %u out of synch, changing "#x" from %"z" to %"z".", ref, x, x + y - ya); x += y - ya; } MERGEDELTA(pS->body, body, structureCheckLastBody[player], "u"); MERGEDELTA(pS->rot.direction, rot.direction, structureCheckLastDirection[player].direction, "d"); MERGEDELTA(pS->rot.pitch, rot.pitch, structureCheckLastDirection[player].pitch, "d"); MERGEDELTA(pS->rot.roll, rot.roll, structureCheckLastDirection[player].roll, "d"); #undef MERGEDELTA syncDebugStructure(pS, '>'); } else { debug(LOG_ERROR, "We got a structure %u synch, but can't find the structure.", ref); } NETend(); return true; }
bool recvResearchStatus(NETQUEUE queue) { STRUCTURE *psBuilding; PLAYER_RESEARCH *pPlayerRes; RESEARCH_FACILITY *psResFacilty; RESEARCH *pResearch; uint8_t player; bool bStart; uint32_t index, structRef; NETbeginDecode(queue, GAME_RESEARCHSTATUS); NETuint8_t(&player); NETbool(&bStart); NETuint32_t(&structRef); NETuint32_t(&index); NETend(); syncDebug("player%d, bStart%d, structRef%u, index%u", player, bStart, structRef, index); if (player >= MAX_PLAYERS || index >= asResearch.size()) { debug(LOG_ERROR, "Bad GAME_RESEARCHSTATUS received, player is %d, index is %u", (int)player, index); return false; } if (!canGiveOrdersFor(queue.index, player)) { debug(LOG_WARNING, "Droid order for wrong player."); syncDebug("Wrong player."); return false; } int prevResearchState = 0; if (aiCheckAlliances(selectedPlayer, player)) { prevResearchState = intGetResearchState(); } pPlayerRes = &asPlayerResList[player][index]; // psBuilding may be null if finishing if (bStart) // Starting research { psBuilding = IdToStruct(structRef, player); // Set that facility to research if (psBuilding && psBuilding->pFunctionality) { psResFacilty = (RESEARCH_FACILITY *) psBuilding->pFunctionality; popStatusPending(*psResFacilty); // Research is no longer pending, as it's actually starting now. if (psResFacilty->psSubject) { cancelResearch(psBuilding, ModeImmediate); } // Set the subject up pResearch = &asResearch[index]; psResFacilty->psSubject = pResearch; // Start the research MakeResearchStarted(pPlayerRes); psResFacilty->timeStartHold = 0; } } // Finished/cancelled research else { // If they completed the research, we're done if (IsResearchCompleted(pPlayerRes)) { return true; } // If they did not say what facility it was, look it up orselves if (!structRef) { // Go through the structs to find the one doing this topic for (psBuilding = apsStructLists[player]; psBuilding; psBuilding = psBuilding->psNext) { if (psBuilding->pStructureType->type == REF_RESEARCH && psBuilding->status == SS_BUILT && ((RESEARCH_FACILITY *) psBuilding->pFunctionality)->psSubject && ((RESEARCH_FACILITY *) psBuilding->pFunctionality)->psSubject->ref - REF_RESEARCH_START == index) { break; } } } else { psBuilding = IdToStruct(structRef, player); } // Stop the facility doing any research if (psBuilding) { cancelResearch(psBuilding, ModeImmediate); popStatusPending(*(RESEARCH_FACILITY *)psBuilding->pFunctionality); // Research cancellation is no longer pending, as it's actually cancelling now. } } if (aiCheckAlliances(selectedPlayer, player)) { intAlliedResearchChanged(); intNotifyResearchButton(prevResearchState); } return true; }
// //////////////////////////////////////////////////////////////////////////// BOOL recvBuildFinished(NETMSG *m) { UDWORD strId;//,i; STRUCTURE *psStr; UWORD x,y,z; UDWORD type,typeindex; UBYTE player; NetGet(m,0,strId); // get the struct id. psStr = IdToStruct(strId,ANYPLAYER); if(psStr) { // make it complete. psStr->currentBuildPts = psStr->pStructureType->buildPoints+1; if(psStr->status != SS_BUILT) { psStr->status = SS_BUILT; buildingComplete(psStr); } NETlogEntry("building finished ok." ,0,0); return TRUE; } // the building wasn't started, so we'll have to just plonk it down in the map. NetGet(m,4,type); // kind of building. NetGet(m,8,x); // x pos NetGet(m,10,y); // y pos NetGet(m,12,z); // z pos player = m->body[14]; // player for(typeindex=0; // find structure target (typeindex<numStructureStats ) && (asStructureStats[typeindex].ref != type); typeindex++); psStr = 0; // check for similar buildings, to avoid overlaps if( TILE_HAS_STRUCTURE(mapTile(x>>TILE_SHIFT,y>>TILE_SHIFT)) ) { // get structure; psStr = getTileStructure(x>>TILE_SHIFT, y>>TILE_SHIFT); if(asStructureStats[typeindex].type == psStr->pStructureType->type) { // correct type, correct location, just rename the id's to sync it.. (urgh) psStr->id = strId; psStr->status = SS_BUILT; buildingComplete(psStr); NETlogEntry("structure id modified" ,0,player); return TRUE; } } psStr = buildStructure(&(asStructureStats[typeindex]), // build the structure. x,y, player,TRUE); if (psStr) { psStr->id = strId; psStr->status = SS_BUILT; buildingComplete(psStr); DBCONPRINTF(ConsoleString,(ConsoleString,"MultiPlayer: Struct not found on recvbuildcomplete :%d",strId )); NETlogEntry("had to plonk down a building" ,0,player); } else { DBCONPRINTF(ConsoleString,(ConsoleString,"MultiPlayer: Struct not found on recvbuildcomplete BUILDIT FAILED TOO!:%d",strId )); NETlogEntry("had to plonk down a building, BUT FAILED OH S**T." ,0,player); } return FALSE; }