/** * @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", _("\nSecured crashed %s (%.0f%%)\n"), UFO_GetName(ufoCraft), cond * 100); else cgi->Cvar_Set("mn_uforecovery_actualufo", _("\nSecured landed %s\n"), UFO_GetName(ufoCraft)); cgi->UI_PushWindow("uforecovery"); } }
/** * @brief Fills the UI with ufo yard data */ static void INS_FillUFOYardData_f (void) { installation_t* ins; cgi->UI_ExecuteConfunc("ufolist_clear"); if (cgi->Cmd_Argc() < 2 || atoi(cgi->Cmd_Argv(1)) < 0) { ins = INS_GetCurrentSelectedInstallation(); if (!ins || ins->installationTemplate->type != INSTALLATION_UFOYARD) ins = INS_GetFirstUFOYard(false); } else { ins = INS_GetByIDX(atoi(cgi->Cmd_Argv(1))); if (!ins) Com_DPrintf(DEBUG_CLIENT, "Installation not founded (idx %i)\n", atoi(cgi->Cmd_Argv(1))); } if (ins) { const nation_t* nat = GEO_GetNation(ins->pos); const int timeToBuild = std::max(0, ins->installationTemplate->buildTime - (ccs.date.day - ins->buildStart)); const char* buildTime = (timeToBuild > 0 && ins->installationStatus == INSTALLATION_UNDER_CONSTRUCTION) ? va(ngettext("%d day", "%d days", timeToBuild), timeToBuild) : "-"; const int freeCap = std::max(0, ins->ufoCapacity.max - ins->ufoCapacity.cur); const char* nationName = nat ? _(nat->name) : ""; cgi->UI_ExecuteConfunc("ufolist_addufoyard %d \"%s\" \"%s\" %d %d \"%s\"", ins->idx, ins->name, nationName, ins->ufoCapacity.max, freeCap, buildTime); US_Foreach(ufo) { if (ufo->installation != ins) continue; const char* ufoName = UFO_GetName(ufo->ufoTemplate); const char* condition = va(_("Condition: %3.0f%%"), ufo->condition * 100); const char* status = US_StoredUFOStatus(ufo); cgi->UI_ExecuteConfunc("ufolist_addufo %d \"%s\" \"%s\" \"%s\" \"%s\"", ufo->idx, ufoName, condition, ufo->ufoTemplate->model, status); } } }
/** * @brief Send Stored UFO data to the UI * @note it's called by 'ui_selectstoredufo' command with a parameter of the stored UFO IDX */ static void US_SelectStoredUfo_f (void) { const storedUFO_t *ufo; if (cgi->Cmd_Argc() < 2 || (ufo = US_GetStoredUFOByIDX(atoi(cgi->Cmd_Argv(1)))) == nullptr) { cgi->UI_ExecuteConfunc("show_storedufo -"); return; } const char *ufoName = UFO_GetName(ufo->ufoTemplate); const char *status = US_StoredUFOStatus(ufo); const char *eta; if (Q_streq(status, "transfering")) { date_t time = Date_Substract(ufo->arrive, ccs.date); eta = CP_SecondConvert(Date_DateToSeconds(&time)); } else { eta = "-"; } cgi->UI_ExecuteConfunc("show_storedufo %d \"%s\" %3.0f \"%s\" \"%s\" \"%s\" \"%s\"", ufo->idx, ufoName, ufo->condition * 100, ufo->ufoTemplate->model, status, eta, ufo->installation->name); }
/** * @brief Function to start UFO recovery process. * @note Command to call this: cp_uforecovery_store_start. */ static void UR_DialogStartStore_f (void) { installation_t *installation = nullptr; int idx; int count = 0; date_t date; if (cgi->Cmd_Argc() < 2) { Com_Printf("Usage: %s <installationIDX>\n", cgi->Cmd_Argv(0)); return; } idx = atoi(cgi->Cmd_Argv(1)); INS_Foreach(i) { if (i->ufoCapacity.max <= 0 || i->ufoCapacity.max <= i->ufoCapacity.cur) continue; if (count == idx) { installation = i; break; } count++; } if (!installation) return; Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("Recovered %s from the battlefield. UFO is being transported to %s."), UFO_GetName(ufoRecovery.ufoTemplate), installation->name); MS_AddNewMessage(_("UFO Recovery"), cp_messageBuffer); date = ccs.date; date.day += (int) RECOVERY_DELAY; US_StoreUFO(ufoRecovery.ufoTemplate, installation, date, ufoRecovery.condition); UR_DialogRecoveryDone(); }
/** * @brief Fills the battery list, descriptions, and weapons in slots * of the basedefence equip menu */ static void BDEF_BaseDefenceMenuUpdate_f (void) { char type[MAX_VAR]; base_t* base = B_GetCurrentSelectedBase(); installation_t* installation = INS_GetCurrentSelectedInstallation(); aircraftItemType_t bdefType; linkedList_t* slotList = nullptr; const bool missileResearched = RS_IsResearched_ptr(RS_GetTechByID("rs_building_missile")); const bool laserResearched = RS_IsResearched_ptr(RS_GetTechByID("rs_building_laser")); if (cgi->Cmd_Argc() != 2) type[0] = '\0'; else Q_strncpyz(type, cgi->Cmd_Argv(1), sizeof(type)); /* don't let old links appear on this menu */ cgi->UI_ResetData(TEXT_BASEDEFENCE_LIST); cgi->UI_ResetData(TEXT_LIST); cgi->UI_ResetData(TEXT_ITEMDESCRIPTION); /* base or installation should not be nullptr because we are in the menu of this base or installation */ if (!base && !installation) return; /* base and installation should not both be set. This function requires one or the other set. */ if (base && installation) { Sys_Error("BDEF_BaseDefenceMenuUpdate_f: Both the base and installation are set"); return; } cgi->Cvar_Set("mn_target", _("None")); cgi->UI_ExecuteConfunc("setautofire disable"); if (installation) { /* Every slot aims the same target */ if (installation->numBatteries) { cgi->UI_ExecuteConfunc("setautofire %i", installation->batteries[0].autofire); if (installation->batteries[0].target) cgi->Cvar_Set("mn_target", "%s", UFO_GetName(installation->batteries[0].target)); } } else if (base) { bool autofire = false; /* Every slot aims the same target */ if (base->numBatteries) { autofire |= base->batteries[0].autofire; if (base->batteries[0].target) cgi->Cvar_Set("mn_target", "%s", UFO_GetName(base->batteries[0].target)); } if (base->numLasers) { autofire |= base->lasers[0].autofire; if (base->lasers[0].target && !base->batteries[0].target) cgi->Cvar_Set("mn_target", "%s", UFO_GetName(base->lasers[0].target)); } if (base->numBatteries || base->numLasers) cgi->UI_ExecuteConfunc("setautofire %i", autofire); } /* Check if we can change to laser or missile */ if (base) { cgi->UI_ExecuteConfunc("set_defencetypes %s %s", (!missileResearched) ? "na" : (base && base->numBatteries > 0) ? "enable" : "disable", (!laserResearched) ? "na" : (base && base->numLasers > 0) ? "enable" : "disable"); } else if (installation) { cgi->UI_ExecuteConfunc("set_defencetypes %s %s", (!missileResearched) ? "na" : (installation && installation->installationStatus == INSTALLATION_WORKING && installation->numBatteries > 0) ? "enable" : "disable", "na"); } if (Q_streq(type, "missile")) bdefType = AC_ITEM_BASE_MISSILE; else if (Q_streq(type, "laser")) bdefType = AC_ITEM_BASE_LASER; else /* info page */ return; /* Check that the base or installation has at least 1 battery */ if (base) { if (base->numBatteries + base->numLasers < 1) { Com_Printf("BDEF_BaseDefenceMenuUpdate_f: there is no defence battery in this base: you shouldn't be in this function.\n"); return; } } else if (installation) { if (installation->installationStatus != INSTALLATION_WORKING) { Com_Printf("BDEF_BaseDefenceMenuUpdate_f: installation isn't working: you shouldn't be in this function.\n"); return; } else if (installation->installationTemplate->maxBatteries < 1) { Com_Printf("BDEF_BaseDefenceMenuUpdate_f: there is no defence battery in this installation: you shouldn't be in this function.\n"); return; } } if (installation) { /* we are in the installation defence menu */ if (installation->installationTemplate->maxBatteries == 0) { cgi->LIST_AddString(&slotList, _("No defence of this type in this installation")); } else { BDEF_FillSlotList(installation->batteries, installation->installationTemplate->maxBatteries, &slotList); } } else if (bdefType == AC_ITEM_BASE_MISSILE) { /* we are in the base defence menu for missile */ if (base->numBatteries == 0) { cgi->LIST_AddString(&slotList, _("No defence of this type in this base")); } else { BDEF_FillSlotList(base->batteries, base->numActiveBatteries, &slotList); } } else if (bdefType == AC_ITEM_BASE_LASER) { /* we are in the base defence menu for laser */ if (base->numLasers == 0) { cgi->LIST_AddString(&slotList, _("No defence of this type in this base")); } else { BDEF_FillSlotList(base->lasers, base->numActiveLasers, &slotList); } } else { Com_Printf("BDEF_BaseDefenceMenuUpdate_f: unknown bdefType.\n"); return; } cgi->UI_RegisterLinkedListText(TEXT_BASEDEFENCE_LIST, slotList); }
/** * @brief Function to start UFO selling process. * @note Command to call this: cp_uforecovery_sell_start. */ static void UR_DialogStartSell_f (void) { int price = -1; const nation_t *nation; int i; if (!ufoRecovery.nation) return; nation = ufoRecovery.nation; i = UR_DialogGetCurrentNationIndex(); price = ufoRecovery.ufoNations[i].price; assert(price >= 0); #if 0 if (ufoRecovery.selectedStorage) { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Sold previously recovered %s from %s to nation %s, gained %i credits."), UFO_TypeToName( ufoRecovery.selectedStorage->ufoTemplate->ufotype), ufoRecovery.selectedStorage->base->name, _(nation->name), price); } else #endif { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Recovered %s from the battlefield. UFO sold to nation %s, gained %i credits."), UFO_GetName(ufoRecovery.ufoTemplate), _(nation->name), price); } MS_AddNewMessage(_("UFO Recovery"), cp_messageBuffer); CP_UpdateCredits(ccs.credits + price); /* update nation happiness */ for (i = 0; i < ccs.numNations; i++) { nation_t *nat = NAT_GetNationByIDX(i); float ufoHappiness; assert(nat); if (nat == nation) /* nation is happy because it got the UFO */ ufoHappiness = HAPPINESS_UFO_SALE_GAIN; else /* nation is unhappy because it wanted the UFO */ ufoHappiness = HAPPINESS_UFO_SALE_LOSS; NAT_SetHappiness(ccs.curCampaign->minhappiness, nat, nat->stats[0].happiness + ufoHappiness); } /* UFO recovery process is done, disable buttons. */ UR_DialogRecoveryDone(); }
/** * @brief Check events for UFOs: Appears or disappears on radars * @return true if any new ufo was detected during this iteration, false otherwise */ bool UFO_CampaignCheckEvents (void) { bool newDetection; aircraft_t* ufo; newDetection = false; /* For each ufo in geoscape */ ufo = nullptr; while ((ufo = UFO_GetNext(ufo)) != nullptr) { char detectedBy[MAX_VAR] = ""; float minDistance = -1; /* detected tells us whether or not a UFO is detected NOW, whereas ufo->detected tells * us whether or not the UFO was detected PREVIOUSLY. */ bool detected = false; base_t* base; /* don't update UFO status id UFO is landed or crashed */ if (ufo->landed) continue; /* note: We can't exit these loops as soon as we found the UFO detected * RADAR_CheckUFOSensored registers the UFO in every radars' detection list * which detect it */ /* Check if UFO is detected by an aircraft */ AIR_Foreach(aircraft) { if (!AIR_IsAircraftOnGeoscape(aircraft)) continue; /* maybe the ufo is already detected, don't reset it */ if (RADAR_CheckUFOSensored(&aircraft->radar, aircraft->pos, ufo, detected | ufo->detected)) { const int distance = GetDistanceOnGlobe(aircraft->pos, ufo->pos); detected = true; if (minDistance < 0 || minDistance > distance) { minDistance = distance; Q_strncpyz(detectedBy, aircraft->name, sizeof(detectedBy)); } } } /* Check if UFO is detected by a base */ base = nullptr; while ((base = B_GetNext(base)) != nullptr) { if (!B_GetBuildingStatus(base, B_POWER)) continue; /* maybe the ufo is already detected, don't reset it */ if (RADAR_CheckUFOSensored(&base->radar, base->pos, ufo, detected | ufo->detected)) { const int distance = GetDistanceOnGlobe(base->pos, ufo->pos); detected = true; if (minDistance < 0 || minDistance > distance) { minDistance = distance; Q_strncpyz(detectedBy, base->name, sizeof(detectedBy)); } } } /* Check if UFO is detected by a radartower */ INS_Foreach(installation) { /* maybe the ufo is already detected, don't reset it */ if (RADAR_CheckUFOSensored(&installation->radar, installation->pos, ufo, detected | ufo->detected)) { const int distance = GetDistanceOnGlobe(installation->pos, ufo->pos); detected = true; if (minDistance < 0 || minDistance > distance) { minDistance = distance; Q_strncpyz(detectedBy, installation->name, sizeof(detectedBy)); } } } /* Check if ufo appears or disappears on radar */ if (detected != ufo->detected) { if (detected) { UFO_DetectNewUFO(ufo); /* if UFO is aiming a PHALANX aircraft, warn player */ if (ufo->aircraftTarget) { /* stop time and notify */ MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("%s is flying toward %s"), UFO_GetName(ufo), ufo->aircraftTarget->name)); /** @todo present a popup with possible orders like: return to base, attack the ufo, try to flee the rockets * @sa UFO_SearchAircraftTarget */ } else { MSO_CheckAddNewMessage(NT_UFO_SPOTTED, _("Notice"), va(_("Our radar detected %s near %s"), UFO_GetName(ufo), detectedBy), MSG_UFOSPOTTED); } newDetection = true; } else if (!detected) { MSO_CheckAddNewMessage(NT_UFO_SIGNAL_LOST, _("Notice"), va(_("Our radar has lost the tracking on %s"), UFO_GetName(ufo)), MSG_UFOLOST); /* Make this UFO undetected */ ufo->detected = false; /* Notify that ufo disappeared */ AIR_AircraftsUFODisappear(ufo); GEO_NotifyUFODisappear(ufo); /* Deactivate Radar overlay */ RADAR_DeactivateRadarOverlay(); } } } return newDetection; }