/** * @brief Function to trigger UFO Recovered event. * @note This function prepares related cvars for the recovery dialog. * @note Command to call this: cp_uforecovery_init. */ static void UR_DialogInit_f (void) { char ufoID[MAX_VAR]; const aircraft_t *ufoCraft; float cond = 1.0f; if (cgi->Cmd_Argc() < 2) { Com_Printf("Usage: %s <ufoID> [UFO-Condition]\n", cgi->Cmd_Argv(0)); return; } Q_strncpyz(ufoID, cgi->Cmd_Argv(1), sizeof(ufoID)); if (cgi->Cmd_Argc() >= 3) cond = atof(cgi->Cmd_Argv(2)); ufoCraft = AIR_GetAircraft(ufoID); /* Fill ufoRecovery structure */ OBJZERO(ufoRecovery); ufoRecovery.ufoTemplate = ufoCraft; ufoRecovery.condition = cond; ufoRecovery.sortedColumn = ORDER_NATION; if (ufoCraft) { if (cond < 1.0) cgi->Cvar_Set("mn_uforecovery_actualufo", va(_("\nSecured crashed %s (%.0f%%)\n"), UFO_GetName(ufoCraft), cond * 100)); else cgi->Cvar_Set("mn_uforecovery_actualufo", va(_("\nSecured landed %s\n"), UFO_GetName(ufoCraft))); cgi->UI_PushWindow("uforecovery"); } }
/** * @brief Prints the UFOpaedia description for aircraft * @note Also checks whether the aircraft tech is already researched or collected * @sa BS_MarketAircraftDescription * @sa UP_Article */ void UP_AircraftDescription (const technology_t* tech) { cgi->INV_ItemDescription(nullptr); /* ensure that the buffer is emptied in every case */ upBuffer[0] = '\0'; if (RS_IsResearched_ptr(tech)) { const aircraft_t* aircraft = AIR_GetAircraft(tech->provides); for (int i = 0; i < AIR_STATS_MAX; i++) { switch (i) { case AIR_STATS_SPEED: /* speed may be converted to km/h : multiply by pi / 180 * earth_radius */ Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i), AIR_AircraftMenuStatsValues(aircraft->stats[i], i)); break; case AIR_STATS_MAXSPEED: /* speed may be converted to km/h : multiply by pi / 180 * earth_radius */ Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i), AIR_AircraftMenuStatsValues(aircraft->stats[i], i)); break; case AIR_STATS_FUELSIZE: Q_strcat(upBuffer, sizeof(upBuffer), _("Operational range:\t%i km\n"), AIR_GetOperationRange(aircraft)); break; case AIR_STATS_ACCURACY: Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i\n"), UP_AircraftStatToName(i), AIR_AircraftMenuStatsValues(aircraft->stats[i], i)); break; default: break; } } const baseCapacities_t cap = AIR_GetCapacityByAircraftWeight(aircraft); const buildingType_t buildingType = B_GetBuildingTypeByCapacity(cap); const building_t* building = B_GetBuildingTemplateByType(buildingType); Q_strcat(upBuffer, sizeof(upBuffer), _("Required Hangar:\t%s\n"), _(building->name)); /* @note: while MAX_ACTIVETEAM limits the number of soldiers on a craft * there is no use to show this in case of an UFO (would be misleading): */ if (!AIR_IsUFO(aircraft)) Q_strcat(upBuffer, sizeof(upBuffer), _("Max. soldiers:\t%i\n"), aircraft->maxTeamSize); } else if (RS_Collected_(tech)) { /** @todo Display crippled info and pre-research text here */ Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this")); } else { Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this")); } cgi->Cvar_Set("mn_upmetadata", "1"); cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, upBuffer); UP_DisplayTechTree(tech); }
/** * @brief sets market prices at start of the game * @sa CP_CampaignInit * @sa B_SetUpFirstBase * @sa BS_Load (Market load function) */ void BS_InitMarket (const campaign_t* campaign) { int i; market_t* market = BS_GetMarket(); for (i = 0; i < cgi->csi->numODs; i++) { const objDef_t* od = INVSH_GetItemByIDX(i); if (market->askItems[i] == 0) { market->askItems[i] = od->price; market->bidItems[i] = floor(market->askItems[i] * BID_FACTOR); } if (campaign->marketDef->numItems[i] <= 0) continue; if (RS_IsResearched_ptr(RS_GetTechForItem(od))) { /* the other relevant values were already set above */ market->numItems[i] = campaign->marketDef->numItems[i]; } else { Com_Printf("BS_InitMarket: Could not add item %s to the market - not marked as researched in campaign %s\n", od->id, campaign->id); } } for (i = 0; i < AIRCRAFTTYPE_MAX; i++) { const char* name = cgi->Com_DropShipTypeToShortName((humanAircraftType_t)i); const aircraft_t* aircraft = AIR_GetAircraft(name); if (market->askAircraft[i] == 0) { market->askAircraft[i] = aircraft->price; market->bidAircraft[i] = floor(market->askAircraft[i] * BID_FACTOR); } if (campaign->marketDef->numAircraft[i] <= 0) continue; if (RS_IsResearched_ptr(aircraft->tech)) { /* the other relevant values were already set above */ market->numAircraft[i] = campaign->marketDef->numAircraft[i]; } else { Com_Printf("BS_InitMarket: Could not add aircraft %s to the market - not marked as researched in campaign %s\n", aircraft->id, campaign->id); } } }
/** * @brief make number of items change every day. * @sa CP_CampaignRun * @sa daily called * @note This function makes items number on market slowly reach the asymptotic number of items defined in equipment.ufo * If an item has just been researched, it's not available on market until RESEARCH_LIMIT_DELAY days is reached. */ void CP_CampaignRunMarket (campaign_t* campaign) { int i; const float TYPICAL_TIME = 10.f; /**< Number of days to reach the asymptotic number of items */ const int RESEARCH_LIMIT_DELAY = 30; /**< Numbers of days after end of research to wait in order to have * items added on market */ market_t* market = BS_GetMarket(); assert(campaign->marketDef); assert(campaign->asymptoticMarketDef); for (i = 0; i < cgi->csi->numODs; i++) { const objDef_t* od = INVSH_GetItemByIDX(i); const technology_t* tech = RS_GetTechForItem(od); int asymptoticNumber; if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numItems[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) { /* if items are researched for more than RESEARCH_LIMIT_DELAY or was on the initial market, * there number tend to the value defined in equipment.ufo. * This value is the asymptotic value if it is not 0, or initial value else */ asymptoticNumber = campaign->asymptoticMarketDef->numItems[i] ? campaign->asymptoticMarketDef->numItems[i] : campaign->marketDef->numItems[i]; } else { /* items that have just been researched don't appear on market, but they can disappear */ asymptoticNumber = 0; } /* Store the evolution of the market in currentEvolution */ market->currentEvolutionItems[i] += (asymptoticNumber - market->numItems[i]) / TYPICAL_TIME; /* Check if new items appeared or disappeared on market */ if (fabs(market->currentEvolutionItems[i]) >= 1.0f) { const int num = (int)(market->currentEvolutionItems[i]); if (num >= 0) BS_AddItemToMarket(od, num); else BS_RemoveItemFromMarket(od, -num); market->currentEvolutionItems[i] -= num; } } for (i = 0; i < AIRCRAFTTYPE_MAX; i++) { const humanAircraftType_t type = (humanAircraftType_t)i; const char* aircraftID = cgi->Com_DropShipTypeToShortName(type); const aircraft_t* aircraft = AIR_GetAircraft(aircraftID); const technology_t* tech = aircraft->tech; int asymptoticNumber; if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numAircraft[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) { /* if aircraft is researched for more than RESEARCH_LIMIT_DELAY or was on the initial market, * there number tend to the value defined in equipment.ufo. * This value is the asymptotic value if it is not 0, or initial value else */ asymptoticNumber = campaign->asymptoticMarketDef->numAircraft[i] ? campaign->asymptoticMarketDef->numAircraft[i] : campaign->marketDef->numAircraft[i]; } else { /* items that have just been researched don't appear on market, but they can disappear */ asymptoticNumber = 0; } /* Store the evolution of the market in currentEvolution */ market->currentEvolutionAircraft[i] += (asymptoticNumber - market->numAircraft[i]) / TYPICAL_TIME; /* Check if new items appeared or disappeared on market */ if (fabs(market->currentEvolutionAircraft[i]) >= 1.0f) { const int num = (int)(market->currentEvolutionAircraft[i]); if (num >= 0) BS_AddAircraftToMarket(aircraft, num); else BS_RemoveAircraftFromMarket(aircraft, -num); market->currentEvolutionAircraft[i] -= num; } } }
/** * @brief Load callback for xml savegames * @param[in] p XML Node structure, where we get the information from * @sa PR_SaveXML * @sa SAV_GameLoadXML */ bool PR_LoadXML (xmlNode_t* p) { xmlNode_t* node = cgi->XML_GetNode(p, SAVE_PRODUCE_PRODUCTION); for (xmlNode_t* snode = cgi->XML_GetNode(node, SAVE_PRODUCE_QUEUE); snode; snode = cgi->XML_GetNextNode(snode, node, SAVE_PRODUCE_QUEUE)) { xmlNode_t* ssnode; const int baseIDX = cgi->XML_GetInt(snode, SAVE_PRODUCE_QUEUEIDX, MAX_BASES); base_t* base = B_GetBaseByIDX(baseIDX); production_queue_t* pq; if (base == nullptr) { Com_Printf("Invalid production queue index %i\n", baseIDX); continue; } pq = PR_GetProductionForBase(base); for (ssnode = cgi->XML_GetNode(snode, SAVE_PRODUCE_ITEM); pq->numItems < MAX_PRODUCTIONS && ssnode; ssnode = cgi->XML_GetNextNode(ssnode, snode, SAVE_PRODUCE_ITEM)) { const char* s1 = cgi->XML_GetString(ssnode, SAVE_PRODUCE_ITEMID); production_t* prod = &pq->items[pq->numItems]; prod->idx = pq->numItems; prod->amount = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_AMOUNT, 0); prod->frame = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_PROGRESS, 0); /* amount */ if (prod->amount <= 0) { Com_Printf("PR_LoadXML: Production with amount <= 0 dropped (baseidx=%i, production idx=%i).\n", baseIDX, pq->numItems); continue; } /* item */ if (s1[0] != '\0') PR_SetData(&prod->data, PRODUCTION_TYPE_ITEM, INVSH_GetItemByID(s1)); /* UFO */ const int ufoIDX = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_UFOIDX, -1); if (ufoIDX != -1) { storedUFO_t* ufo = US_GetStoredUFOByIDX(ufoIDX); if (!ufo) { Com_Printf("PR_LoadXML: Could not find ufo idx: %i\n", ufoIDX); continue; } PR_SetData(&prod->data, PRODUCTION_TYPE_DISASSEMBLY, ufo); PR_SetUFODisassembly(prod); } /* aircraft */ const char* s2 = cgi->XML_GetString(ssnode, SAVE_PRODUCE_AIRCRAFTID); if (s2[0] != '\0') PR_SetData(&prod->data, PRODUCTION_TYPE_AIRCRAFT, AIR_GetAircraft(s2)); if (!PR_IsDataValid(&prod->data)) { Com_Printf("PR_LoadXML: Production is not an item an aircraft nor a disassembly\n"); continue; } pq->numItems++; } } return true; }