UFO: Alien Invasion
cp_uforecovery.cpp
Go to the documentation of this file.
1 
8 /*
9 Copyright (C) 2002-2022 UFO: Alien Invasion.
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, 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"
36 #include "save/save_uforecovery.h"
37 #include "cp_component.h"
38 
39 /*==================================
40 Backend functions
41 ==================================*/
42 
47 void UR_ProcessActive (void)
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 
100 storedUFO_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;
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 {
137  ufo.status = SUFO_RECOVERED;
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 */
168  ufo->installation->ufoCapacity.cur--;
169  cgi->LIST_Remove(&ccs.storedUFOs, (void*)ufo);
170 }
171 
172 
180 int 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  }
215  US_RemoveStoredUFO(ufo);
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 
243  ufo->installation->ufoCapacity.cur--;
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 
261 storedUFO_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 {
302 
303  cgi->Com_RegisterConstList(saveStoredUFOConstants);
304  US_Foreach(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());
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 
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
389 
392 static 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 
416 static 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 
460 static 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 
477 static const cmdList_t debugStoredUfosCmds[] = {
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 };
489 void UR_InitStartup (void)
490 {
492  cgi->Cmd_TableAddList(debugStoredUfosCmds);
493 }
494 
498 void UR_Shutdown (void)
499 {
500  cgi->LIST_Delete(&ccs.storedUFOs);
501 
503  cgi->Cmd_TableRemoveList(debugStoredUfosCmds);
504 }
void UR_ShutdownCallbacks(void)
xmlNode_t *IMPORT * XML_GetNode(xmlNode_t *parent, const char *name)
int numAircraftTemplates
Definition: cp_campaign.h:385
Header file for Aircraft and item components.
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...
Store capacities in base.
Definition: cp_capacity.h:41
byte month
Definition: cp_time.h:38
A base with all it&#39;s data.
Definition: cp_base.h:84
short year
Definition: cp_time.h:37
#define _(String)
Definition: cl_shared.h:44
char * id
Definition: cp_aircraft.h:120
int US_StoredUFOCount(void)
Returns the number of storedUFOs.
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
#define PR_GetProductionForBase(base)
Definition: cp_produce.h:96
#define SAVE_UFORECOVERY_UFOIDX
Class describing a point of time.
Definition: DateTime.h:30
storedUFO_t * US_StoreUFO(const aircraft_t *ufoTemplate, installation_t *installation, DateTime &date, float condition)
Adds an UFO to the storage.
char name[MAX_VAR]
Definition: cp_base.h:86
const aircraft_t * AIR_GetAircraft(const char *name)
Searches the global array of aircraft types for a given aircraft.
#define SAVE_UFORECOVERY_UFO
#define SAVE_UFORECOVERY_DATE
int US_UFOsInStorage(const aircraft_t *ufoTemplate, const installation_t *installation)
Returns the number of UFOs stored (on an installation or anywhere)
byte day
Definition: cp_time.h:39
const char *IMPORT * Cmd_Argv(int n)
const char * UFO_GetName(const aircraft_t *ufocraft)
Returns name of the UFO if UFO has been researched.
Definition: cp_ufo.cpp:243
void US_RemoveUFOsExceedingCapacity(installation_t *installation)
Removes ufos which are over the storing capacity.
Structure for stored UFOs.
A installation with all it&#39;s data.
#define SAVE_UFORECOVERY_UFOID
void PR_QueueNext(base_t *base)
Queues the next production in the queue.
Definition: cp_produce.cpp:345
UFO recovery and storing callback header file.
const char * Date_GetMonthName(int month)
Returns the short monthame to the given month index.
Definition: cp_time.cpp:250
void UR_InitStartup(void)
Init actions for ufostoring-subsystem.
components_t * COMP_GetComponentsByID(const char *id)
Returns components definition by ID.
#define xmlNode_t
Definition: xml.h:24
bool US_LoadXML(xmlNode_t *p)
Load callback for xml savegames.
linkedList_t * storedUFOs
Definition: cp_campaign.h:315
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define SAVE_STOREDUFOSTATUS_NAMESPACE
void US_RemoveStoredUFO(storedUFO_t *ufo)
Removes an UFO from the storage.
XML tag constants for savegame.
#define ERR_DROP
Definition: common.h:211
#define DEBUG_CLIENT
Definition: defines.h:59
DateTime arrive
void UR_InitCallbacks(void)
#define MAX_VAR
Definition: shared.h:36
xmlNode_t *IMPORT * XML_GetDate(xmlNode_t *parent, const char *name, int *day, int *sec)
#define US_Foreach(var)
void UR_ProcessActive(void)
Function to process active recoveries.
void RS_MarkCollected(technology_t *tech)
Marks a give technology as collected.
capacities_t ufoCapacity
const char *IMPORT * XML_GetString(xmlNode_t *parent, const char *name)
Human readable time information in the game.
Definition: cp_time.h:36
base_t * PR_ProductionBase(const production_t *production)
Returns the base pointer the production belongs to.
Definition: cp_produce.cpp:651
const cgame_import_t * cgi
bool US_SaveXML(xmlNode_t *p)
Save callback for savegames in XML Format.
UFO recovery and storing.
ccs_t ccs
Definition: cp_campaign.cpp:63
char id[MAX_VAR]
int ufosStored
Definition: cp_statistics.h:48
aircraft_t aircraftTemplates[MAX_AIRCRAFT]
Definition: cp_campaign.h:384
production_t * disassembly
Campaign geoscape time header.
xmlNode_t *IMPORT * XML_GetNextNode(xmlNode_t *current, xmlNode_t *parent, const char *name)
Header for Geoscape management.
static const constListEntry_t saveStoredUFOConstants[]
void PR_QueueDelete(base_t *base, production_queue_t *queue, int index)
Delete the selected entry from the queue.
Definition: cp_produce.cpp:281
const aircraft_t * ufoTemplate
char cp_messageBuffer[MAX_MESSAGE_TEXT]
Definition: cp_messages.cpp:33
QGL_EXTERN GLuint count
Definition: r_gl.h:99
CGAME_HARD_LINKED_FUNCTIONS linkedList_t * LIST_Add(linkedList_t **listDest, void const *data, size_t length)
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
byte min
Definition: cp_time.h:41
storedUFO_t * US_GetStoredUFOByIDX(const int idx)
Returns a stored ufo.
void RS_CheckRequirements(void)
Checks if running researches still meet their requirements.
An aircraft with all it&#39;s data.
Definition: cp_aircraft.h:115
void UR_Shutdown(void)
Closing actions for ufostoring-subsystem.
struct technology_s * tech
Definition: cp_aircraft.h:163
#define RECOVERY_DELAY
Header file for aircraft stuff.
storedUFOStatus_t
different statuses for a stored UFO
char name[MAX_VAR]
stats_t campaignStats
Definition: cp_campaign.h:379
QGL_EXTERN GLint i
Definition: r_gl.h:113
installation_t * installation
#define SAVE_UFORECOVERY_STOREDUFOS
#define SAVE_UFORECOVERY_INSTALLATIONIDX
class DateTime date
Definition: cp_campaign.h:246
Definition: cmd.h:86
bool US_TransferUFO(storedUFO_t *ufo, installation_t *ufoyard)
Start transferring of a stored UFO.
storedUFOStatus_t status
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
Header file for single player campaign control.
#define SAVE_UFORECOVERY_STATUS
xmlNode_t *IMPORT * XML_AddNode(xmlNode_t *parent, const char *name)
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
vec3_t pos
Definition: cp_base.h:91
const char *IMPORT * Com_GetConstVariable(const char *space, int value)
byte hour
Definition: cp_time.h:40
#define SAVE_UFORECOVERY_CONDITION
struct components_s * comp
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition: mathlib.cpp:171
installation_t * INS_GetByIDX(int idx)
Get installation by it&#39;s index.