Bug Summary

File:client/cgame/campaign/cp_uforecovery_callbacks.cpp
Location:line 294, column 16
Description:Called function pointer is null (null dereference)

Annotated Source Code

1/**
2 * @file
3 * @brief UFO recovery and storing callback functions
4 * @note UFO recovery functions with UR_*
5 * @note UFO storing functions with US_*
6 */
7
8/*
9Copyright (C) 2002-2012 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 "../../cl_shared.h"
28#include "../../ui/ui_dataids.h"
29#include "cp_campaign.h"
30#include "cp_ufo.h"
31#include "cp_uforecovery.h"
32#include "cp_uforecovery_callbacks.h"
33#include "cp_map.h"
34#include "cp_time.h"
35
36/**
37 * @brief Entries on Sell UFO dialog
38 */
39typedef struct ufoRecoveryNation_s {
40 const nation_t *nation;
41 int price; /**< price proposed by nation. */
42} ufoRecoveryNation_t;
43
44/**
45 * @brief Pointer to compare function
46 * @note This function is used by sorting algorithm.
47 */
48typedef int (*COMP_FUNCTION)(ufoRecoveryNation_t *a, ufoRecoveryNation_t *b);
49
50/**
51 * @brief Constants for Sell UFO menu order
52 */
53typedef enum {
54 ORDER_NATION,
55 ORDER_PRICE,
56 ORDER_HAPPINESS,
57
58 MAX_ORDER
59} ufoRecoveryNationOrder_t;
60
61/** @sa ufoRecoveries_t */
62typedef struct ufoRecovery_s {
63 const aircraft_t *ufoTemplate; /**< the ufo type of the current ufo recovery */
64 const nation_t *nation; /**< selected nation to sell to for current ufo recovery */
65 bool recoveryDone; /**< recoveryDone? Then the buttons are disabled */
66 float condition; /**< How much the UFO is damaged - used for disassembies */
67 ufoRecoveryNation_t UFONations[MAX_NATIONS8]; /**< Sorted array of nations. */
68 ufoRecoveryNationOrder_t sortedColumn; /**< Column sell sorted by */
69 bool sortDescending; /**< ascending (false) / descending (true) */
70} ufoRecovery_t;
71
72static ufoRecovery_t ufoRecovery;
73
74/**
75 * @brief Updates UFO recovery process.
76 */
77static void UR_DialogRecoveryDone (void)
78{
79 ufoRecovery.recoveryDone = true;
80}
81
82/**
83 * @brief Function to trigger UFO Recovered event.
84 * @note This function prepares related cvars for the recovery dialog.
85 * @note Command to call this: cp_uforecovery_init.
86 */
87static void UR_DialogInit_f (void)
88{
89 char ufoID[MAX_VAR64];
90 const aircraft_t *ufoCraft;
91 float cond = 1.0f;
92
93 if (Cmd_Argc() < 2) {
94 Com_Printf("Usage: %s <ufoID> [UFO-Condition]\n", Cmd_Argv(0));
95 return;
96 }
97
98 Q_strncpyz(ufoID, Cmd_Argv(1), sizeof(ufoID))Q_strncpyzDebug( ufoID, Cmd_Argv(1), sizeof(ufoID), "src/client/cgame/campaign/cp_uforecovery_callbacks.cpp"
, 98 )
;
99
100 if (Cmd_Argc() >= 3)
101 cond = atof(Cmd_Argv(2));
102
103 ufoCraft = AIR_GetAircraft(ufoID);
104
105 /* Fill ufoRecovery structure */
106 OBJZERO(ufoRecovery)(memset(&((ufoRecovery)), (0), sizeof((ufoRecovery))));
107 ufoRecovery.ufoTemplate = ufoCraft;
108 ufoRecovery.condition = cond;
109 ufoRecovery.sortedColumn = ORDER_NATION;
110
111 if (ufoCraft) {
112 if (cond < 1.0)
113 Cvar_Set("mn_uforecovery_actualufo", va(_("\nSecured crashed %s (%.0f%%)\n")gettext("\nSecured crashed %s (%.0f%%)\n"), UFO_AircraftToIDOnGeoscape(ufoCraft), cond * 100));
114 else
115 Cvar_Set("mn_uforecovery_actualufo", va(_("\nSecured landed %s\n")gettext("\nSecured landed %s\n"), UFO_AircraftToIDOnGeoscape(ufoCraft)));
116
117 cgi->UI_PushWindow("uforecovery");
118 }
119}
120
121/**
122 * @brief Function to initialize list of storage locations for recovered UFO.
123 * @note Command to call this: cp_uforecovery_store_init.
124 * @sa UR_ConditionsForStoring
125 */
126static void UR_DialogInitStore_f (void)
127{
128 int count = 0;
129 linkedList_t *recoveryYardName = NULL__null;
130 linkedList_t *recoveryYardCapacity = NULL__null;
131 static char cap[MAX_VAR64];
132
133 /* Do nothing if recovery process is finished. */
134 if (ufoRecovery.recoveryDone)
135 return;
136
137 /* Check how many bases can store this UFO. */
138 INS_Foreach(installation)for (bool installation__break = false, installation__once = true
; installation__once; installation__once = false) for (linkedList_t
const* installation__iter = (ccs.installations); ! installation__break
&& installation__iter;) for (installation_t* const installation
= ( installation__break = installation__once = true, (installation_t
*) installation__iter->data); installation__once; installation__break
= installation__once = false) if ( installation__iter = installation__iter
->next, false) {} else
{
139 const capacities_t *capacity;
140
141 capacity = &installation->ufoCapacity;
142 if (capacity->max > 0 && capacity->max > capacity->cur) {
143 Com_sprintf(cap, lengthof(cap)(sizeof(cap) / sizeof(*(cap))), "%i/%i", (capacity->max - capacity->cur), capacity->max);
144 LIST_AddString(&recoveryYardName, installation->name);
145 LIST_AddString(&recoveryYardCapacity, cap);
146 count++;
147 }
148 }
149
150 if (count == 0) {
151 /* No UFO base with proper conditions, show a hint and disable list. */
152 LIST_AddString(&recoveryYardName, _("No free UFO yard available.")gettext("No free UFO yard available."));
153 cgi->UI_ExecuteConfunc("uforecovery_tabselect sell");
154 cgi->UI_ExecuteConfunc("btbasesel disable");
155 } else {
156 cgi->UI_ExecuteConfunc("cp_basesel_select 0");
157 cgi->UI_ExecuteConfunc("btbasesel enable");
158 }
159 cgi->UI_RegisterLinkedListText(TEXT_UFORECOVERY_UFOYARDS, recoveryYardName);
160 cgi->UI_RegisterLinkedListText(TEXT_UFORECOVERY_CAPACITIES, recoveryYardCapacity);
161}
162
163/**
164 * @brief Function to start UFO recovery process.
165 * @note Command to call this: cp_uforecovery_store_start.
166 */
167static void UR_DialogStartStore_f (void)
168{
169 installation_t *installation = NULL__null;
170 int idx;
171 int count = 0;
172 date_t date;
173
174 if (Cmd_Argc() < 2) {
175 Com_Printf("Usage: %s <installationIDX>\n", Cmd_Argv(0));
176 return;
177 }
178
179 idx = atoi(Cmd_Argv(1));
180
181 INS_Foreach(i)for (bool i__break = false, i__once = true; i__once; i__once =
false) for (linkedList_t const* i__iter = (ccs.installations
); ! i__break && i__iter;) for (installation_t* const
i = ( i__break = i__once = true, (installation_t*) i__iter->
data); i__once; i__break = i__once = false) if ( i__iter = i__iter
->next, false) {} else
{
182 if (i->ufoCapacity.max <= 0 || i->ufoCapacity.max <= i->ufoCapacity.cur)
183 continue;
184
185 if (count == idx) {
186 installation = i;
187 break;
188 }
189 count++;
190 }
191
192 if (!installation)
193 return;
194
195 Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer)(sizeof(cp_messageBuffer) / sizeof(*(cp_messageBuffer))), _("Recovered %s from the battlefield. UFO is being transported to %s.")gettext("Recovered %s from the battlefield. UFO is being transported to %s."
)
,
196 UFO_AircraftToIDOnGeoscape(ufoRecovery.ufoTemplate), installation->name);
197 MS_AddNewMessage(_("UFO Recovery")gettext("UFO Recovery"), cp_messageBuffer);
198 date = ccs.date;
199 date.day += (int) RECOVERY_DELAY2.0f;
200
201 US_StoreUFO(ufoRecovery.ufoTemplate, installation, date, ufoRecovery.condition);
202 UR_DialogRecoveryDone();
203}
204
205/**
206 * @brief Build the Sell UFO dialog's nationlist
207 */
208static void UR_DialogFillNations (void)
209{
210 int i;
211 linkedList_t *nationList = NULL__null;
212
213 for (i = 0; i < ccs.numNations; i++) {
214 const nation_t *nation = ufoRecovery.UFONations[i].nation;
215 if (nation) {
216 char row[512];
217 Com_sprintf(row, lengthof(row)(sizeof(row) / sizeof(*(row))), "%s\t\t\t%i\t\t%s", _(nation->name)gettext(nation->name),
218 ufoRecovery.UFONations[i].price, NAT_GetHappinessString(nation));
219 LIST_AddString(&nationList, row);
220 }
221 }
222
223 cgi->UI_RegisterLinkedListText(TEXT_UFORECOVERY_NATIONS, nationList);
224}
225
226/**
227 * @brief Compare nations by nation name.
228 * @param[in] a First item to compare
229 * @param[in] b Second item to compare
230 * @sa UR_SortNations
231 */
232static int UR_CompareByName (ufoRecoveryNation_t *a, ufoRecoveryNation_t *b)
233{
234 return strcmp(_(a->nation->name)gettext(a->nation->name), _(b->nation->name)gettext(b->nation->name));
235}
236
237/**
238 * @brief Compare nations by price.
239 * @param[in] a First item to compare
240 * @param[in] b Second item to compare
241 * @return 1 if a > b
242 * @return -1 if b > a
243 * @return 0 if a == b
244 * @sa UR_SortNations
245 */
246static int UR_CompareByPrice (ufoRecoveryNation_t *a, ufoRecoveryNation_t *b)
247{
248 if (a->price > b->price)
249 return 1;
250 if (a->price < b->price)
251 return -1;
252 return 0;
253}
254
255/**
256 * @brief Compare nations by happiness.
257 * @param[in] a First item to compare
258 * @param[in] b Second item to compare
259 * @return 1 if a > b
260 * @return -1 if b > a
261 * @return 0 if a == b
262 * @sa UR_SortNations
263 */
264static int UR_CompareByHappiness (ufoRecoveryNation_t *a, ufoRecoveryNation_t *b)
265{
266 const nationInfo_t *statsA = NAT_GetCurrentMonthInfo(a->nation);
267 const nationInfo_t *statsB = NAT_GetCurrentMonthInfo(b->nation);
268
269 if (statsA->happiness > statsB->happiness)
270 return 1;
271 if (statsA->happiness < statsB->happiness)
272 return -1;
273 return 0;
274}
275
276/**
277 * @brief Sort nations
278 * @note uses Bubble sort algorithm
279 * @param[in] comp Compare function
280 * @param[in] order Ascending/Descending order
281 * @sa UR_CompareByName
282 * @sa UR_CompareByPrice
283 * @sa UR_CompareByHappiness
284 */
285static void UR_SortNations (COMP_FUNCTION comp, bool order)
286{
287 int i;
288
289 for (i = 0; i < ccs.numNations; i++) {
5
Loop condition is true. Entering loop body
290 bool swapped = false;
291 int j;
292
293 for (j = 0; j < ccs.numNations - 1; j++) {
6
Loop condition is true. Entering loop body
294 int value = (*comp)(&ufoRecovery.UFONations[j], &ufoRecovery.UFONations[j + 1]);
7
Called function pointer is null (null dereference)
295 ufoRecoveryNation_t tmp;
296
297 if (order)
298 value *= -1;
299 if (value > 0) {
300 /* swap nations */
301 tmp = ufoRecovery.UFONations[j];
302 ufoRecovery.UFONations[j] = ufoRecovery.UFONations[j + 1];
303 ufoRecovery.UFONations[j + 1] = tmp;
304 swapped = true;
305 }
306 }
307 if (!swapped)
308 break;
309 }
310}
311
312/**
313 * @brief Returns the sort function for a column
314 * @param[in] column Column ordertype.
315 */
316static COMP_FUNCTION UR_GetSortFunctionByColumn (ufoRecoveryNationOrder_t column)
317{
318 switch (column) {
319 case ORDER_NATION:
320 return UR_CompareByName;
321 case ORDER_PRICE:
322 return UR_CompareByPrice;
323 case ORDER_HAPPINESS:
324 return UR_CompareByHappiness;
325 default:
326 Com_Printf("UR_DialogSortByColumn_f: Invalid sort option!\n");
327 return NULL__null;
328 }
329}
330
331/**
332 * @brief Function to initialize list to sell recovered UFO to desired nation.
333 * @note Command to call this: cp_uforecovery_sell_init.
334 */
335static void UR_DialogInitSell_f (void)
336{
337 int i;
338
339 /* Do nothing if recovery process is finished. */
340 if (ufoRecovery.recoveryDone)
1
Taking false branch
341 return;
342 /* Do nothing without a ufoTemplate set */
343 if (!ufoRecovery.ufoTemplate)
2
Taking false branch
344 return;
345
346 for (i = 0; i < ccs.numNations; i++) {
3
Loop condition is false. Execution continues on line 358
347 const nation_t *nation = NAT_GetNationByIDX(i);
348 const nationInfo_t *stats = NAT_GetCurrentMonthInfo(nation);
349 int price;
350
351 price = (int) (ufoRecovery.ufoTemplate->price * (.85f + frand() * .3f));
352 /* Nation will pay less if corrupted */
353 price = (int) (price * exp(-stats->xviInfection / 20.0f));
354
355 ufoRecovery.UFONations[i].nation = nation;
356 ufoRecovery.UFONations[i].price = price;
357 }
358 UR_SortNations(UR_GetSortFunctionByColumn(ufoRecovery.sortedColumn), ufoRecovery.sortDescending);
4
Calling 'UR_SortNations'
359 UR_DialogFillNations();
360 cgi->UI_ExecuteConfunc("btnatsel disable");
361}
362
363/**
364 * @brief Returns the index of the selected nation in SellUFO list
365 */
366static int UR_DialogGetCurrentNationIndex (void)
367{
368 int i;
369
370 for (i = 0; i < ccs.numNations; i++)
371 if (ufoRecovery.UFONations[i].nation == ufoRecovery.nation)
372 return i;
373 return -1;
374}
375
376/**
377 * @brief Converts script id string to ordercolumn constant
378 * @param[in] id Script id for order column
379 * @sa ufoRecoveryNationOrder_t
380 */
381static ufoRecoveryNationOrder_t UR_GetOrderTypeByID (const char *id)
382{
383 if (!id)
384 return MAX_ORDER;
385 if (Q_streq(id, "nation")(strcmp(id, "nation") == 0))
386 return ORDER_NATION;
387 if (Q_streq(id, "price")(strcmp(id, "price") == 0))
388 return ORDER_PRICE;
389 if (Q_streq(id, "happiness")(strcmp(id, "happiness") == 0))
390 return ORDER_HAPPINESS;
391 return MAX_ORDER;
392}
393
394/**
395 * @brief Sort Sell UFO dialog
396 */
397static void UR_DialogSortByColumn_f (void)
398{
399 COMP_FUNCTION comp = 0;
400 ufoRecoveryNationOrder_t column;
401
402 if (Cmd_Argc() < 2) {
403 Com_Printf("Usage: %s <nation|price|happiness>\n", Cmd_Argv(0));
404 return;
405 }
406
407 column = UR_GetOrderTypeByID(Cmd_Argv(1));
408 if (ufoRecovery.sortedColumn != column) {
409 ufoRecovery.sortDescending = false;
410 ufoRecovery.sortedColumn = column;
411 } else {
412 ufoRecovery.sortDescending = !ufoRecovery.sortDescending;
413 }
414
415 comp = UR_GetSortFunctionByColumn(column);
416 if (comp) {
417 int index;
418
419 UR_SortNations(comp, ufoRecovery.sortDescending);
420 UR_DialogFillNations();
421
422 /* changed line selection corresponding to current nation */
423 index = UR_DialogGetCurrentNationIndex();
424 if (index != -1)
425 cgi->UI_ExecuteConfunc("cp_nationsel_select %d", index);
426 }
427}
428
429/**
430 * @brief Finds the nation to which recovered UFO will be sold.
431 * @note The nation selection is being done here.
432 * @note Callback command: cp_uforecovery_nationlist_click.
433 */
434static void UR_DialogSelectSellNation_f (void)
435{
436 int num;
437 const nation_t *nation;
438
439 if (Cmd_Argc() < 2) {
440 Com_Printf("Usage: %s <nationid>\n", Cmd_Argv(0));
441 return;
442 }
443
444 num = atoi(Cmd_Argv(1));
445
446 /* don't do anything if index is higher than visible nations */
447 if (0 > num || num >= ccs.numNations)
448 return;
449
450 nation = ufoRecovery.UFONations[num].nation;
451
452 ufoRecovery.nation = nation;
453 Com_DPrintf(DEBUG_CLIENT0x20, "CP_UFORecoveryNationSelectPopup_f: picked nation: %s\n", nation->name);
454
455 Cvar_Set("mission_recoverynation", _(nation->name)gettext(nation->name));
456 cgi->UI_ExecuteConfunc("btnatsel enable");
457}
458
459/**
460 * @brief Function to start UFO selling process.
461 * @note Command to call this: cp_uforecovery_sell_start.
462 */
463static void UR_DialogStartSell_f (void)
464{
465 int price = -1;
466 const nation_t *nation;
467 int i;
468
469 if (!ufoRecovery.nation)
470 return;
471
472 nation = ufoRecovery.nation;
473
474 i = UR_DialogGetCurrentNationIndex();
475 price = ufoRecovery.UFONations[i].price;
476
477 assert(price >= 0)(__builtin_expect(!(price >= 0), 0) ? __assert_rtn(__func__
, "src/client/cgame/campaign/cp_uforecovery_callbacks.cpp", 477
, "price >= 0") : (void)0)
;
478#if 0
479 if (ufoRecovery.selectedStorage) {
480 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Sold previously recovered %s from %s to nation %s, gained %i credits.")gettext("Sold previously recovered %s from %s to nation %s, gained %i credits."
)
, UFO_TypeToName(
481 ufoRecovery.selectedStorage->ufoTemplate->ufotype), ufoRecovery.selectedStorage->base->name, _(nation->name)gettext(nation->name), price);
482 } else
483#endif
484 {
485 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Recovered %s from the battlefield. UFO sold to nation %s, gained %i credits.")gettext("Recovered %s from the battlefield. UFO sold to nation %s, gained %i credits."
)
, UFO_AircraftToIDOnGeoscape(ufoRecovery.ufoTemplate), _(nation->name)gettext(nation->name), price);
486 }
487 MS_AddNewMessage(_("UFO Recovery")gettext("UFO Recovery"), cp_messageBuffer);
488 CP_UpdateCredits(ccs.credits + price);
489
490 /* update nation happiness */
491 for (i = 0; i < ccs.numNations; i++) {
492 nation_t *nat = NAT_GetNationByIDX(i);
493 float ufoHappiness;
494
495 assert(nat)(__builtin_expect(!(nat), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_uforecovery_callbacks.cpp"
, 495, "nat") : (void)0)
;
496 if (nat == nation)
497 /* nation is happy because it got the UFO */
498 ufoHappiness = HAPPINESS_UFO_SALE_GAIN0.02;
499 else
500 /* nation is unhappy because it wanted the UFO */
501 ufoHappiness = HAPPINESS_UFO_SALE_LOSS0.005;
502
503 NAT_SetHappiness(ccs.curCampaign->minhappiness, nat, nat->stats[0].happiness + ufoHappiness);
504 }
505
506 /* UFO recovery process is done, disable buttons. */
507 UR_DialogRecoveryDone();
508}
509
510/**
511 * @brief Returns string representation of the stored UFO's status
512 * @note uses stored ufo status and disassembly
513 */
514const char *US_StoredUFOStatus (const storedUFO_t *ufo)
515{
516 assert(ufo)(__builtin_expect(!(ufo), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_uforecovery_callbacks.cpp"
, 516, "ufo") : (void)0)
;
517
518 if (ufo->disassembly != NULL__null)
519 return "disassembling";
520
521 switch (ufo->status) {
522 case SUFO_STORED:
523 return "stored";
524 case SUFO_RECOVERED:
525 case SUFO_TRANSFERED:
526 return "transfering";
527 default:
528 return "unknown";
529 }
530}
531
532/**
533 * @brief Send Stored UFO data to the UI
534 * @note it's called by 'ui_selectstoredufo' command with a parameter of the stored UFO IDX
535 */
536static void US_SelectStoredUfo_f (void)
537{
538 const storedUFO_t *ufo;
539
540 if (Cmd_Argc() < 2 || (ufo = US_GetStoredUFOByIDX(atoi(Cmd_Argv(1)))) == NULL__null) {
541 cgi->UI_ExecuteConfunc("show_storedufo -");
542 } else {
543 const char *ufoName = UFO_AircraftToIDOnGeoscape(ufo->ufoTemplate);
544 const char *status = US_StoredUFOStatus(ufo);
545 const char *eta;
546
547 if (Q_streq(status, "transfering")(strcmp(status, "transfering") == 0)) {
548 date_t time = Date_Substract(ufo->arrive, ccs.date);
549 eta = CP_SecondConvert(Date_DateToSeconds(&time));
550 } else {
551 eta = "-";
552 }
553
554 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);
555 }
556}
557
558
559/**
560 * @brief Destroys a stored UFO
561 * @note it's called by 'ui_destroystoredufo' command with a parameter of the stored UFO IDX and a confirmation value
562 */
563static void US_DestroySoredUFO_f (void)
564{
565 if (Cmd_Argc() < 2) {
566 Com_DPrintf(DEBUG_CLIENT0x20, "Usage: %s <idx> [0|1]\nWhere the second, optional parameter is the confirmation.\n", Cmd_Argv(0));
567 return;
568 }
569 storedUFO_t *ufo = US_GetStoredUFOByIDX(atoi(Cmd_Argv(1)));
570 if (!ufo) {
571 Com_DPrintf(DEBUG_CLIENT0x20, "Stored UFO with idx: %i does not exist\n", atoi(Cmd_Argv(1)));
572 return;
573 }
574
575 /* Ask 'Are you sure?' by default */
576 if (Cmd_Argc() < 3 || !atoi(Cmd_Argv(2))) {
577 char command[128];
578
579 Com_sprintf(command, sizeof(command), "ui_destroystoredufo %d 1;ui_pop; mn_installation_select %d;", ufo->idx, ufo->installation->idx);
580 cgi->UI_PopupButton(_("Destroy stored UFO")gettext("Destroy stored UFO"), _("Do you really want to destroy this stored UFO?")gettext("Do you really want to destroy this stored UFO?"),
581 command, _("Destroy")gettext("Destroy"), _("Destroy stored UFO")gettext("Destroy stored UFO"),
582 "ui_pop;", _("Cancel")gettext("Cancel"), _("Forget it")gettext("Forget it"),
583 NULL__null, NULL__null, NULL__null);
584 return;
585 }
586 US_RemoveStoredUFO(ufo);
587 Cmd_ExecuteString(va("mn_installation_select %d", ufo->installation->idx));
588}
589
590/**
591 * @brief Fills UFO Yard UI with transfer destinations
592 */
593static void US_FillUFOTransfer_f (void)
594{
595 if (Cmd_Argc() < 2) {
596 Com_DPrintf(DEBUG_CLIENT0x20, "Usage: %s <idx>\n", Cmd_Argv(0));
597 return;
598 }
599
600 storedUFO_t *ufo = US_GetStoredUFOByIDX(atoi(Cmd_Argv(1)));
601 if (!ufo) {
602 Com_DPrintf(DEBUG_CLIENT0x20, "Stored UFO with idx: %i does not exist\n", atoi(Cmd_Argv(1)));
603 return;
604 }
605
606 cgi->UI_ExecuteConfunc("ufotransferlist_clear");
607 INS_ForeachOfType(ins, INSTALLATION_UFOYARD)for (bool ins__break = false, ins__once = true; ins__once; ins__once
= false) for (linkedList_t const* ins__iter = (ccs.installations
); ! ins__break && ins__iter;) for (installation_t* const
ins = ( ins__break = ins__once = true, (installation_t*) ins__iter
->data); ins__once; ins__break = ins__once = false) if ( ins__iter
= ins__iter->next, false) {} else if ((ins)->installationTemplate
->type != (INSTALLATION_UFOYARD)) continue; else
{
608 if (ins == ufo->installation)
609 continue;
610 nation_t *nat = MAP_GetNation(ins->pos);
611 const char *nationName = nat ? _(nat->name)gettext(nat->name) : "";
612 const int freeSpace = std::max(0, ins->ufoCapacity.max - ins->ufoCapacity.cur);
613 cgi->UI_ExecuteConfunc("ufotransferlist_addyard %d \"%s\" \"%s\" %d %d", ins->idx, ins->name, nationName, freeSpace, ins->ufoCapacity.max);
614 }
615}
616
617/**
618 * @brief Send Stored UFOs of the destination UFO Yard
619 */
620static void US_FillUFOTransferUFOs_f (void)
621{
622 if (Cmd_Argc() < 2) {
623 Com_DPrintf(DEBUG_CLIENT0x20, "Usage: %s <idx>\n", Cmd_Argv(0));
624 return;
625 }
626
627 installation_t *ins = INS_GetByIDX(atoi(Cmd_Argv(1)));
628 if (!ins) {
629 Com_DPrintf(DEBUG_CLIENT0x20, "Installation with idx: %i does not exist\n", atoi(Cmd_Argv(1)));
630 return;
631 }
632
633 cgi->UI_ExecuteConfunc("ufotransferlist_clearufos %d", ins->idx);
634 US_Foreach(ufo)for (bool ufo__break = false, ufo__once = true; ufo__once; ufo__once
= false) for (linkedList_t const* ufo__iter = (ccs.storedUFOs
); ! ufo__break && ufo__iter;) for (storedUFO_t* const
ufo = ( ufo__break = ufo__once = true, (storedUFO_t*) ufo__iter
->data); ufo__once; ufo__break = ufo__once = false) if ( ufo__iter
= ufo__iter->next, false) {} else
{
635 if (ufo->installation != ins)
636 continue;
637 cgi->UI_ExecuteConfunc("ufotransferlist_addufos %d %d \"%s\"", ins->idx, ufo->idx, ufo->ufoTemplate->model);
638 }
639}
640
641/**
642 * @brief Callback to start the transfer of a stored UFO
643 */
644static void US_TransferUFO_f (void)
645{
646 storedUFO_t *ufo;
647 installation_t *ins = NULL__null;
648
649 if (Cmd_Argc() < 3) {
650 Com_Printf("Usage: %s <stored-ufo-idx> <ufoyard-idx>\n", Cmd_Argv(0));
651 return;
652 }
653 ufo = US_GetStoredUFOByIDX(atoi(Cmd_Argv(1)));
654 if (ufo == NULL__null) {
655 Com_Printf("Stored ufo with idx %i not found.\n", atoi(Cmd_Argv(1)));
656 return;
657 }
658 ins = INS_GetByIDX(atoi(Cmd_Argv(2)));
659 if (!ins) {
660 Com_Printf("Installation with idx: %i does not exist\n", atoi(Cmd_Argv(2)));
661 return;
662 }
663 US_TransferUFO(ufo, ins);
664}
665
666void UR_InitCallbacks (void)
667{
668 Cmd_AddCommand("cp_uforecovery_init", UR_DialogInit_f, "Function to trigger UFO Recovered event");
669 Cmd_AddCommand("cp_uforecovery_sell_init", UR_DialogInitSell_f, "Function to initialize sell recovered UFO to desired nation.");
670 Cmd_AddCommand("cp_uforecovery_store_init", UR_DialogInitStore_f, "Function to initialize store recovered UFO in desired base.");
671 Cmd_AddCommand("cp_uforecovery_nationlist_click", UR_DialogSelectSellNation_f, "Callback for recovery sell to nation list.");
672 Cmd_AddCommand("cp_uforecovery_store_start", UR_DialogStartStore_f, "Function to start UFO recovery processing.");
673 Cmd_AddCommand("cp_uforecovery_sell_start", UR_DialogStartSell_f, "Function to start UFO selling processing.");
674 Cmd_AddCommand("cp_uforecovery_sort", UR_DialogSortByColumn_f, "Sorts nations and update ui state.");
675
676 Cmd_AddCommand("ui_selectstoredufo", US_SelectStoredUfo_f, "Send Stored UFO data to the UI");
677 Cmd_AddCommand("ui_destroystoredufo", US_DestroySoredUFO_f, "Destroy stored UFO");
678 Cmd_AddCommand("ui_fill_ufotransfer", US_FillUFOTransfer_f, "Fills UFO Yard UI with transfer destinations");
679 Cmd_AddCommand("ui_selecttransferyard", US_FillUFOTransferUFOs_f, "Send Stored UFOs of the destination UFO Yard");
680 Cmd_AddCommand("ui_transferufo", US_TransferUFO_f, "Transfer stored UFO to another UFO Yard");
681}
682
683void UR_ShutdownCallbacks (void)
684{
685 Cmd_RemoveCommand("ui_transferufo");
686 Cmd_RemoveCommand("ui_selecttransferyard");
687 Cmd_RemoveCommand("ui_fill_ufotransfer");
688 Cmd_RemoveCommand("ui_destroystoredufo");
689 Cmd_RemoveCommand("ui_selectstoredufo");
690
691 Cmd_RemoveCommand("cp_uforecovery_init");
692 Cmd_RemoveCommand("cp_uforecovery_sell_init");
693 Cmd_RemoveCommand("cp_uforecovery_store_init");
694 Cmd_RemoveCommand("cp_uforecovery_nationlist_click");
695 Cmd_RemoveCommand("cp_uforecovery_store_start");
696 Cmd_RemoveCommand("cp_uforecovery_sell_start");
697 Cmd_RemoveCommand("cp_uforecovery_sort");
698}