File: | client/cgame/campaign/cp_uforecovery_callbacks.cpp |
Location: | line 294, column 16 |
Description: | Called function pointer is null (null dereference) |
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 | /* | ||
9 | Copyright (C) 2002-2012 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 "../../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 | */ | ||
39 | typedef 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 | */ | ||
48 | typedef int (*COMP_FUNCTION)(ufoRecoveryNation_t *a, ufoRecoveryNation_t *b); | ||
49 | |||
50 | /** | ||
51 | * @brief Constants for Sell UFO menu order | ||
52 | */ | ||
53 | typedef enum { | ||
54 | ORDER_NATION, | ||
55 | ORDER_PRICE, | ||
56 | ORDER_HAPPINESS, | ||
57 | |||
58 | MAX_ORDER | ||
59 | } ufoRecoveryNationOrder_t; | ||
60 | |||
61 | /** @sa ufoRecoveries_t */ | ||
62 | typedef 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 | |||
72 | static ufoRecovery_t ufoRecovery; | ||
73 | |||
74 | /** | ||
75 | * @brief Updates UFO recovery process. | ||
76 | */ | ||
77 | static 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 | */ | ||
87 | static 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 | */ | ||
126 | static 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 | */ | ||
167 | static 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 | */ | ||
208 | static 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 | */ | ||
232 | static 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 | */ | ||
246 | static 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 | */ | ||
264 | static 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 | */ | ||
285 | static void UR_SortNations (COMP_FUNCTION comp, bool order) | ||
286 | { | ||
287 | int i; | ||
288 | |||
289 | for (i = 0; i < ccs.numNations; i++) { | ||
| |||
290 | bool swapped = false; | ||
291 | int j; | ||
292 | |||
293 | for (j = 0; j < ccs.numNations - 1; j++) { | ||
| |||
294 | int value = (*comp)(&ufoRecovery.UFONations[j], &ufoRecovery.UFONations[j + 1]); | ||
| |||
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 | */ | ||
316 | static 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 | */ | ||
335 | static void UR_DialogInitSell_f (void) | ||
336 | { | ||
337 | int i; | ||
338 | |||
339 | /* Do nothing if recovery process is finished. */ | ||
340 | if (ufoRecovery.recoveryDone) | ||
| |||
341 | return; | ||
342 | /* Do nothing without a ufoTemplate set */ | ||
343 | if (!ufoRecovery.ufoTemplate) | ||
| |||
344 | return; | ||
345 | |||
346 | for (i = 0; i < ccs.numNations; i++) { | ||
| |||
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); | ||
| |||
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 | */ | ||
366 | static 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 | */ | ||
381 | static 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 | */ | ||
397 | static 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 | */ | ||
434 | static 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 | */ | ||
463 | static 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 | */ | ||
514 | const 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 | */ | ||
536 | static 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 | */ | ||
563 | static 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 | */ | ||
593 | static 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 | */ | ||
620 | static 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 | */ | ||
644 | static 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 | |||
666 | void 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 | |||
683 | void 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 | } |