// recv a research topic that is now complete. static bool recvResearch(NETQUEUE queue) { uint8_t player; uint32_t index; int i; PLAYER_RESEARCH *pPlayerRes; NETbeginDecode(queue, GAME_DEBUG_FINISH_RESEARCH); NETuint8_t(&player); NETuint32_t(&index); NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to finish research for player %u.", NetPlay.players[queue.index].position); return false; } syncDebug("player%d, index%u", player, index); if (player >= MAX_PLAYERS || index >= asResearch.size()) { debug(LOG_ERROR, "Bad GAME_DEBUG_FINISH_RESEARCH received, player is %d, index is %u", (int)player, index); return false; } pPlayerRes = &asPlayerResList[player][index]; syncDebug("research status = %d", pPlayerRes->ResearchStatus & RESBITS); if (!IsResearchCompleted(pPlayerRes)) { MakeResearchCompleted(pPlayerRes); researchResult(index, player, false, NULL, true); } // Update allies research accordingly if (game.type == SKIRMISH) { for (i = 0; i < MAX_PLAYERS; i++) { if (alliances[i][player] == ALLIANCE_FORMED) { pPlayerRes = &asPlayerResList[i][index]; if (!IsResearchCompleted(pPlayerRes)) { // Do the research for that player MakeResearchCompleted(pPlayerRes); researchResult(index, i, false, NULL, true); } } } } return true; }
// //////////////////////////////////////////////////////////////////////////// // give technologies. static void giftResearch(uint8_t from, uint8_t to, bool send) { int i; uint32_t dummy = 0; if (send) { uint8_t giftType = RESEARCH_GIFT; NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT); NETuint8_t(&giftType); NETuint8_t(&from); NETuint8_t(&to); NETuint32_t(&dummy); NETend(); } else if (alliancesCanGiveResearchAndRadar(game.alliance)) { if (to == selectedPlayer) { CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives You Technology Documents"), getPlayerName(from))); } // For each topic for (i = 0; i < asResearch.size(); i++) { // If they have it and we don't research it if (IsResearchCompleted(&asPlayerResList[from][i]) && !IsResearchCompleted(&asPlayerResList[to][i])) { MakeResearchCompleted(&asPlayerResList[to][i]); researchResult(i, to, false, NULL, true); } } } }
// //////////////////////////////////////////////////////////////////////////// // give technologies. static void giftResearch(uint8_t from, uint8_t to, BOOL send) { PLAYER_RESEARCH *pR, *pRto; int i; uint32_t dummy = 0; if (send) { uint8_t giftType = RESEARCH_GIFT; NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT); NETuint8_t(&giftType); NETuint8_t(&from); NETuint8_t(&to); NETuint32_t(&dummy); NETend(); } else { if (to == selectedPlayer) { CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives You Technology Documents"), getPlayerName(from))); } pR = asPlayerResList[from]; pRto = asPlayerResList[to]; // For each topic for (i = 0; i < numResearch; i++) { // If they have it and we don't research it if (IsResearchCompleted(&pR[i]) && !IsResearchCompleted(&pRto[i])) { MakeResearchCompleted(&pRto[i]); researchResult(i, to, false, NULL, true); } } } }
/* process the results of a completed research topic */ void researchResult(UDWORD researchIndex, UBYTE player, bool bDisplay, STRUCTURE *psResearchFacility, bool bTrigger) { RESEARCH *pResearch = &asResearch[researchIndex]; MESSAGE *pMessage; //the message gets sent to console char consoleMsg[MAX_RESEARCH_MSG_SIZE]; ASSERT_OR_RETURN(, researchIndex < asResearch.size(), "Invalid research index %u", researchIndex); syncDebug("researchResult(%u, %u, …)", researchIndex, player); MakeResearchCompleted(&asPlayerResList[player][researchIndex]); //check for structures to be made available for (unsigned short pStructureResult : pResearch->pStructureResults) { if (apStructTypeLists[player][pStructureResult] != REDUNDANT) { apStructTypeLists[player][pStructureResult] = AVAILABLE; } } //check for structures to be made redundant for (unsigned short pRedStruct : pResearch->pRedStructs) { apStructTypeLists[player][pRedStruct] = REDUNDANT; } //check for component replacement if (!pResearch->componentReplacement.empty()) { for (auto &ri : pResearch->componentReplacement) { COMPONENT_STATS *pOldComp = ri.pOldComponent; replaceComponent(ri.pNewComponent, pOldComp, player); apCompLists[player][pOldComp->compType][pOldComp->index] = REDUNDANT; } } //check for artefacts to be made available for (auto &componentResult : pResearch->componentResults) { //determine the type of artefact COMPONENT_TYPE type = componentResult->compType; //set the component state to AVAILABLE int compInc = componentResult->index; if (apCompLists[player][type][compInc] != REDUNDANT) { apCompLists[player][type][compInc] = AVAILABLE; } //check for default sensor if (type == COMP_SENSOR && (asSensorStats + compInc)->location == LOC_DEFAULT) { aDefaultSensor[player] = compInc; } //check for default ECM else if (type == COMP_ECM && (asECMStats + compInc)->location == LOC_DEFAULT) { aDefaultECM[player] = compInc; } //check for default Repair else if (type == COMP_REPAIRUNIT && (asRepairStats + compInc)->location == LOC_DEFAULT) { aDefaultRepair[player] = compInc; enableSelfRepair(player); } } //check for artefacts to be made redundant for (auto &pRedArtefact : pResearch->pRedArtefacts) { COMPONENT_TYPE type = pRedArtefact->compType; apCompLists[player][type][pRedArtefact->index] = REDUNDANT; } //Add message to player's list if Major Topic if ((pResearch->techCode == TC_MAJOR) && bDisplay) { //only play sound if major topic if (player == selectedPlayer) { audio_QueueTrack(ID_SOUND_MAJOR_RESEARCH); } //check there is viewdata for the research topic - just don't add message if not! if (pResearch->pViewData != nullptr) { pMessage = addMessage(MSG_RESEARCH, false, player); if (pMessage != nullptr) { pMessage->pViewData = pResearch->pViewData; jsDebugMessageUpdate(); } } } else if (player == selectedPlayer && bDisplay) { audio_QueueTrack(ID_SOUND_RESEARCH_COMPLETED); } if (player == selectedPlayer && bDisplay) { //add console text message if (pResearch->pViewData != nullptr) { snprintf(consoleMsg, MAX_RESEARCH_MSG_SIZE, _("Research completed: %s"), _(pResearch->pViewData->textMsg[0].toUtf8().c_str())); addConsoleMessage(consoleMsg, LEFT_JUSTIFY, SYSTEM_MESSAGE); } else { addConsoleMessage(_("Research Completed"), LEFT_JUSTIFY, SYSTEM_MESSAGE); } } if (psResearchFacility) { psResearchFacility->pFunctionality->researchFacility.psSubject = nullptr; // Make sure topic is cleared } if ((bMultiPlayer || player == selectedPlayer) && bTrigger) { psCBLastResearch = pResearch; // Fun with pointers. Throw them into some random global variable, and get Nexus to absorb them. CBResFacilityOwner = player; psCBLastResStructure = psResearchFacility; eventFireCallbackTrigger((TRIGGER_TYPE)CALL_RESEARCHCOMPLETED); psCBLastResStructure = nullptr; CBResFacilityOwner = -1; psCBLastResearch = nullptr; } triggerEventResearched(pResearch, psResearchFacility, player); }