UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_uforecovery.cpp
Go to the documentation of this file.
1
7
8/*
9Copyright (C) 2002-2025 UFO: Alien Invasion.
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25*/
26
27#include "../../DateTime.h"
28#include "../../cl_shared.h"
29#include "cp_campaign.h"
30#include "cp_ufo.h"
31#include "cp_geoscape.h"
32#include "cp_time.h"
33#include "cp_uforecovery.h"
35#include "cp_aircraft.h"
37#include "cp_component.h"
38
39/*==================================
40Backend functions
41==================================*/
42
48{
49 US_Foreach(ufo) {
50 assert(ufo->ufoTemplate);
51 assert(ufo->ufoTemplate->tech);
52
53 if (ufo->status == SUFO_STORED)
54 continue;
55 if (ufo->arrive > ccs.date)
56 continue;
57
58 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s was transferred to %s."), UFO_GetName(ufo->ufoTemplate), ufo->installation->name);
59 switch (ufo->status) {
60 case SUFO_RECOVERED:
62 break;
63 case SUFO_TRANSFERED:
65 break;
66 default:
67 break;
68 }
69 ufo->status = SUFO_STORED;
70
71 if (!ufo->ufoTemplate->tech->statusCollected)
72 RS_MarkCollected(ufo->ufoTemplate->tech);
73 }
74}
75
76/* ==== UFO Storing stuff ==== */
77
84{
85 US_Foreach(ufo) {
86 if (ufo->idx == idx)
87 return ufo;
88 }
89 return nullptr;
90}
91
100storedUFO_t* US_StoreUFO (const aircraft_t* ufoTemplate, installation_t* installation, DateTime& date, float condition)
101{
102 if (!ufoTemplate) {
103 cgi->Com_DPrintf(DEBUG_CLIENT, "US_StoreUFO: Invalid aircraft (UFO) Template.\n");
104 return nullptr;
105 }
106
107 if (!installation) {
108 cgi->Com_DPrintf(DEBUG_CLIENT, "US_StoreUFO: Invalid Installation\n");
109 return nullptr;
110 }
111
112 if (installation->ufoCapacity.cur >= installation->ufoCapacity.max) {
113 cgi->Com_DPrintf(DEBUG_CLIENT, "US_StoreUFO: Installation is full with UFOs.\n");
114 return nullptr;
115 }
116
117 /* we can store it there */
118 storedUFO_t ufo;
119 ufo.idx = ccs.campaignStats.ufosStored++;
120 Q_strncpyz(ufo.id, ufoTemplate->id, sizeof(ufo.id));
121 ufo.comp = COMP_GetComponentsByID(ufo.id);
122 assert(ufo.comp);
123
124 ufo.installation = installation;
125 installation->ufoCapacity.cur++;
126
127 assert(ufoTemplate->tech);
128
129 ufo.ufoTemplate = ufoTemplate;
130 ufo.disassembly = nullptr;
131
132 ufo.arrive = DateTime(date);
133 if (ccs.date > ufo.arrive) {
134 ufo.status = SUFO_STORED;
136 } else {
138 }
139 ufo.condition = std::min(std::max(0.0f, condition), 1.0f);
140
141 return &LIST_Add(&ccs.storedUFOs, ufo);
142}
143
149{
150 assert(ufo);
151
152 /* Stop disassembling */
153 if (ufo->disassembly) {
154 base_t* prodBase = PR_ProductionBase(ufo->disassembly);
155
156 assert(prodBase);
157
158 if (ufo->disassembly->idx == 0)
159 PR_QueueNext(prodBase);
160 else
161 PR_QueueDelete(prodBase, PR_GetProductionForBase(prodBase), ufo->disassembly->idx);
162 }
163
164 /* Check all researches their requirements may broke */
166
167 /* remove ufo */
169 cgi->LIST_Remove(&ccs.storedUFOs, (void*)ufo);
170}
171
172
180int US_UFOsInStorage (const aircraft_t* ufoTemplate, const installation_t* installation)
181{
182 int count = 0;
183
184 US_Foreach(ufo) {
185 if (ufo->ufoTemplate != ufoTemplate)
186 continue;
187 if (installation && ufo->installation != installation)
188 continue;
189 if (ufo->status != SUFO_STORED)
190 continue;
191
192 count++;
193 }
194
195 return count;
196}
197
203{
204 if (!installation)
205 cgi->Com_Error(ERR_DROP, "US_RemoveUFOsExceedingCapacity: No installation given!\n");
206
207 const capacities_t* ufoCap = &installation->ufoCapacity;
208
209 US_Foreach(ufo) {
210 if (ufoCap->cur <= ufoCap->max)
211 break;
212 if (ufo->installation != installation) {
213 continue;
214 }
216 }
217}
218
226{
227 if (!ufo)
228 cgi->Com_Error(ERR_DROP, "No UFO cannot be transferred!");
229 if (!ufoyard)
230 cgi->Com_Error(ERR_DROP, "UFO cannot be transferred to void!");
231 /* only stored ufo can be transferred */
232 if (ufo->status != SUFO_STORED)
233 return false;
234 /* UFO being disassembled cannot be transferred*/
235 if (ufo->disassembly != nullptr)
236 return false;
237 /* UFO is in the same yard - no need of transfer */
238 if (ufo->installation == ufoyard)
239 return false;
240 if (ufoyard->ufoCapacity.cur >= ufoyard->ufoCapacity.max)
241 return false;
242
244 ufo->status = SUFO_TRANSFERED;
245 ufo->arrive = ccs.date + DateTime((int)RECOVERY_DELAY, 0);
246 ufo->installation = ufoyard;
247 ufoyard->ufoCapacity.cur++;
248
249 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("UFO transport started, cargo is being transported to %s"), ufoyard->name);
251
252 return true;
253}
254
261storedUFO_t* US_GetClosestStoredUFO (const aircraft_t* ufoTemplate, const base_t* base)
262{
263 float minDistance = -1;
264 storedUFO_t* closestUFO = nullptr;
265
266 US_Foreach(ufo) {
267 float distance = 0;
268
269 if (ufoTemplate && ufo->ufoTemplate != ufoTemplate)
270 continue;
271 if (ufo->status != SUFO_STORED)
272 continue;
273 assert(ufo->installation);
274 if (base)
275 distance = GetDistanceOnGlobe(ufo->installation->pos, base->pos);
276
277 if (minDistance < 0 || minDistance > distance) {
278 minDistance = distance;
279 closestUFO = ufo;
280 }
281 }
282 return closestUFO;
283}
284
289{
290 return cgi->LIST_Count(ccs.storedUFOs);
291}
292
300{
301 xmlNode_t* node = cgi->XML_AddNode(p, SAVE_UFORECOVERY_STOREDUFOS);
302
303 cgi->Com_RegisterConstList(saveStoredUFOConstants);
304 US_Foreach(ufo) {
305 xmlNode_t* snode = cgi->XML_AddNode(node, SAVE_UFORECOVERY_UFO);
306
307 cgi->XML_AddInt(snode, SAVE_UFORECOVERY_UFOIDX, ufo->idx);
308 cgi->XML_AddString(snode, SAVE_UFORECOVERY_UFOID, ufo->id);
309 cgi->XML_AddDate(snode, SAVE_UFORECOVERY_DATE, ufo->arrive.getDateAsDays(), ufo->arrive.getTimeAsSeconds());
310 cgi->XML_AddString(snode, SAVE_UFORECOVERY_STATUS, cgi->Com_GetConstVariable(SAVE_STOREDUFOSTATUS_NAMESPACE, ufo->status));
311 cgi->XML_AddFloat(snode, SAVE_UFORECOVERY_CONDITION, ufo->condition);
312
313 if (ufo->installation)
314 cgi->XML_AddInt(snode, SAVE_UFORECOVERY_INSTALLATIONIDX, ufo->installation->idx);
315 }
316 cgi->Com_UnregisterConstList(saveStoredUFOConstants);
317 return true;
318}
319
327{
328 xmlNode_t* node, *snode;
329
330 node = cgi->XML_GetNode(p, SAVE_UFORECOVERY_STOREDUFOS);
331
332 cgi->Com_RegisterConstList(saveStoredUFOConstants);
333 for (snode = cgi->XML_GetNode(node, SAVE_UFORECOVERY_UFO); snode;
334 snode = cgi->XML_GetNextNode(snode, node, SAVE_UFORECOVERY_UFO)) {
335 const char* id = cgi->XML_GetString(snode, SAVE_UFORECOVERY_STATUS);
336 storedUFO_t ufo;
337 int statusIDX;
338
339 /* ufo->idx */
340 ufo.idx = cgi->XML_GetInt(snode, SAVE_UFORECOVERY_UFOIDX, -1);
341 if (ufo.idx < 0) {
342 cgi->Com_Printf("Invalid or no IDX defined for stored UFO.\n");
343 continue;
344 }
345 /* ufo->status */
346 if (!cgi->Com_GetConstIntFromNamespace(SAVE_STOREDUFOSTATUS_NAMESPACE, id, &statusIDX)) {
347 cgi->Com_Printf("Invalid storedUFOStatus '%s'\n", id);
348 continue;
349 }
350 ufo.status = (storedUFOStatus_t)statusIDX;
351 /* ufo->installation */
352 ufo.installation = INS_GetByIDX(cgi->XML_GetInt(snode, SAVE_UFORECOVERY_INSTALLATIONIDX, -1));
353 if (!ufo.installation) {
354 cgi->Com_Printf("UFO has no/invalid installation assigned\n");
355 continue;
356 }
358 cgi->Com_Printf("UFO Yard %i if full!\n", ufo.installation->idx);
359 continue;
360 }
362 /* ufo->id */
363 Q_strncpyz(ufo.id, cgi->XML_GetString(snode, SAVE_UFORECOVERY_UFOID), sizeof(ufo.id));
364 /* ufo->ufoTemplate */
365 ufo.ufoTemplate = AIR_GetAircraft(ufo.id);
366 if (!ufo.ufoTemplate) {
367 cgi->Com_Printf("UFO has no/invalid aircraftTemplare assigned\n");
368 continue;
369 }
370 ufo.comp = COMP_GetComponentsByID(ufo.id);
371 if (!ufo.comp) {
372 cgi->Com_Printf("UFO has no/invalid components set\n");
373 continue;
374 }
375 int date;
376 int time;
377 cgi->XML_GetDate(snode, SAVE_UFORECOVERY_DATE, &date, &time);
378 ufo.arrive = DateTime(date, time);
379 ufo.condition = cgi->XML_GetFloat(snode, SAVE_UFORECOVERY_CONDITION, 1.0f);
380 /* disassembly is set by production savesystem later but only for UFOs that are being disassembled */
381 ufo.disassembly = nullptr;
382 LIST_Add(&ccs.storedUFOs, ufo);
383 }
384 cgi->Com_UnregisterConstList(saveStoredUFOConstants);
385 return true;
386}
387
388#ifdef DEBUG
392static void US_ListStoredUFOs_f (void)
393{
394 US_Foreach(ufo) {
395 const base_t* prodBase = PR_ProductionBase(ufo->disassembly);
396 dateLong_t date;
397
398 cgi->Com_Printf("IDX: %i\n", ufo->idx);
399 cgi->Com_Printf("id: %s\n", ufo->id);
400 cgi->Com_Printf("stored at %s\n", (ufo->installation) ? ufo->installation->name : "NOWHERE");
401
402 CP_DateConvertLong(ufo->arrive, &date);
403 cgi->Com_Printf("arrived at: %i %s %02i, %02i:%02i\n", date.year,
404 Date_GetMonthName(date.month - 1), date.day, date.hour, date.min);
405
406 if (ufo->ufoTemplate->tech->base)
407 cgi->Com_Printf("tech being researched at %s\n", ufo->ufoTemplate->tech->base->name);
408 if (prodBase)
409 cgi->Com_Printf("being disassembled at %s\n", prodBase->name);
410 }
411}
412
416static void US_StoreUFO_f (void)
417{
418 char ufoId[MAX_VAR];
419
420 if (cgi->Cmd_Argc() <= 2) {
421 cgi->Com_Printf("Usage: %s <ufoType> <installationIdx>\n", cgi->Cmd_Argv(0));
422 return;
423 }
424
425 Q_strncpyz(ufoId, cgi->Cmd_Argv(1), sizeof(ufoId));
426 int installationIDX = atoi(cgi->Cmd_Argv(2));
427
428 /* Get The UFO Yard */
429 if (installationIDX < 0) {
430 cgi->Com_Printf("US_StoreUFO_f: Invalid Installation index.\n");
431 return;
432 }
433 installation_t* installation = INS_GetByIDX(installationIDX);
434 if (!installation) {
435 cgi->Com_Printf("US_StoreUFO_f: There is no Installation: idx=%i.\n", installationIDX);
436 return;
437 }
438
439 /* Get UFO Type */
441 aircraft_t* ufoType = nullptr;
442 for (int i = 0; i < ccs.numAircraftTemplates; i++) {
443 if (strstr(ccs.aircraftTemplates[i].id, ufoId)) {
444 ufoType = &ccs.aircraftTemplates[i];
445 break;
446 }
447 }
448 if (ufoType == nullptr) {
449 cgi->Com_Printf("US_StoreUFO_f: In valid UFO Id.\n");
450 return;
451 }
452
453 DateTime date = DateTime(ccs.date);
454 US_StoreUFO(ufoType, installation, date, 1.0f);
455}
456
460static void US_RemoveStoredUFO_f (void)
461{
462 if (cgi->Cmd_Argc() < 2) {
463 cgi->Com_Printf("Usage: %s <idx>\n", cgi->Cmd_Argv(0));
464 return;
465 } else {
466 const int idx = atoi(cgi->Cmd_Argv(1));
467 storedUFO_t* storedUFO = US_GetStoredUFOByIDX(idx);
468 if (!storedUFO) {
469 cgi->Com_Printf("US_RemoveStoredUFO_f: No such ufo index.\n");
470 return;
471 }
472 US_RemoveStoredUFO(storedUFO);
473 }
474}
475#endif
476
478#ifdef DEBUG
479 {"debug_liststoredufos", US_ListStoredUFOs_f, "Debug function to list UFOs in Hangars."},
480 {"debug_storeufo", US_StoreUFO_f, "Debug function to Add UFO to Hangars."},
481 {"debug_removestoredufo", US_RemoveStoredUFO_f, "Debug function to Remove UFO from Hangars."},
482#endif
483 {nullptr, nullptr, nullptr}
484};
485
489void UR_InitStartup (void)
490{
492 cgi->Cmd_TableAddList(debugStoredUfosCmds);
493}
494
498void UR_Shutdown (void)
499{
500 cgi->LIST_Delete(&ccs.storedUFOs);
501
503 cgi->Cmd_TableRemoveList(debugStoredUfosCmds);
504}
DateTime class definition.
CGAME_HARD_LINKED_FUNCTIONS linkedList_t * LIST_Add(linkedList_t **listDest, void const *data, size_t length)
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
Class describing a point of time.
Definition DateTime.h:31
#define ERR_DROP
Definition common.h:211
const aircraft_t * AIR_GetAircraft(const char *name)
Searches the global array of aircraft types for a given aircraft.
Header file for aircraft stuff.
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
components_t * COMP_GetComponentsByID(const char *id)
Returns components definition by ID.
Header file for Aircraft and item components.
Header for Geoscape management.
installation_t * INS_GetByIDX(int idx)
Get installation by it's index.
uiMessageListNodeMessage_t * MSO_CheckAddNewMessage(const notify_t messagecategory, const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup)
Adds a new message to message stack. It uses message settings to verify whether sound should be playe...
@ NT_TRANSFER_STARTED
@ NT_TRANSFER_UFORECOVERY_FINISHED
char cp_messageBuffer[MAX_MESSAGE_TEXT]
@ MSG_TRANSFERFINISHED
Definition cp_messages.h:44
void PR_QueueDelete(base_t *base, production_queue_t *queue, int index)
Delete the selected entry from the queue.
base_t * PR_ProductionBase(const production_t *production)
Returns the base pointer the production belongs to.
void PR_QueueNext(base_t *base)
Queues the next production in the queue.
#define PR_GetProductionForBase(base)
Definition cp_produce.h:96
void RS_MarkCollected(technology_t *tech)
Marks a give technology as collected.
void RS_CheckRequirements(void)
Checks if running researches still meet their requirements.
void CP_DateConvertLong(const DateTime &date, dateLong_t *dateLong)
Converts a date from the engine in a (longer) human-readable format.
Definition cp_time.cpp:73
const char * Date_GetMonthName(int month)
Returns the short monthame to the given month index.
Definition cp_time.cpp:250
Campaign geoscape time header.
const char * UFO_GetName(const aircraft_t *ufocraft)
Returns name of the UFO if UFO has been researched.
Definition cp_ufo.cpp:243
bool US_SaveXML(xmlNode_t *p)
Save callback for savegames in XML Format.
int US_StoredUFOCount(void)
Returns the number of storedUFOs.
storedUFO_t * US_GetStoredUFOByIDX(const int idx)
Returns a stored ufo.
void UR_Shutdown(void)
Closing actions for ufostoring-subsystem.
bool US_LoadXML(xmlNode_t *p)
Load callback for xml savegames.
static const cmdList_t debugStoredUfosCmds[]
storedUFO_t * US_GetClosestStoredUFO(const aircraft_t *ufoTemplate, const base_t *base)
get the closest stored ufo (of a type) from a base
void US_RemoveStoredUFO(storedUFO_t *ufo)
Removes an UFO from the storage.
storedUFO_t * US_StoreUFO(const aircraft_t *ufoTemplate, installation_t *installation, DateTime &date, float condition)
Adds an UFO to the storage.
void US_RemoveUFOsExceedingCapacity(installation_t *installation)
Removes ufos which are over the storing capacity.
void UR_InitStartup(void)
Init actions for ufostoring-subsystem.
int US_UFOsInStorage(const aircraft_t *ufoTemplate, const installation_t *installation)
Returns the number of UFOs stored (on an installation or anywhere).
bool US_TransferUFO(storedUFO_t *ufo, installation_t *ufoyard)
Start transferring of a stored UFO.
void UR_ProcessActive(void)
Function to process active recoveries.
UFO recovery and storing.
#define RECOVERY_DELAY
storedUFOStatus_t
different statuses for a stored UFO
@ SUFO_STORED
@ SUFO_RECOVERED
@ SUFO_TRANSFERED
#define US_Foreach(var)
void UR_InitCallbacks(void)
void UR_ShutdownCallbacks(void)
UFO recovery and storing callback header file.
#define DEBUG_CLIENT
Definition defines.h:59
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition mathlib.cpp:171
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN GLint i
Definition r_gl.h:113
XML tag constants for savegame.
#define SAVE_UFORECOVERY_INSTALLATIONIDX
#define SAVE_UFORECOVERY_UFOIDX
#define SAVE_UFORECOVERY_UFOID
static const constListEntry_t saveStoredUFOConstants[]
#define SAVE_STOREDUFOSTATUS_NAMESPACE
#define SAVE_UFORECOVERY_STOREDUFOS
#define SAVE_UFORECOVERY_STATUS
#define SAVE_UFORECOVERY_DATE
#define SAVE_UFORECOVERY_UFO
#define SAVE_UFORECOVERY_CONDITION
#define MAX_VAR
Definition shared.h:36
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
An aircraft with all it's data.
struct technology_s * tech
A base with all it's data.
Definition cp_base.h:84
char name[MAX_VAR]
Definition cp_base.h:86
vec3_t pos
Definition cp_base.h:91
Store capacities in base.
Definition cp_capacity.h:41
Human readable time information in the game.
Definition cp_time.h:36
byte hour
Definition cp_time.h:40
byte month
Definition cp_time.h:38
byte day
Definition cp_time.h:39
byte min
Definition cp_time.h:41
short year
Definition cp_time.h:37
A installation with all it's data.
char name[MAX_VAR]
capacities_t ufoCapacity
Structure for stored UFOs.
production_t * disassembly
struct components_s * comp
DateTime arrive
const aircraft_t * ufoTemplate
storedUFOStatus_t status
char id[MAX_VAR]
installation_t * installation
#define xmlNode_t
Definition xml.h:24