UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_transfer_callbacks.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*/
23
25#include "../../DateTime.h"
26#include "../../cl_shared.h"
27#include "cp_campaign.h"
28#include "cp_capacity.h"
29#include "cp_transfer.h"
30#include "cp_popup.h"
31#include "cp_time.h"
32#include "aliencargo.h"
33#include "aliencontainment.h"
34#include "itemcargo.h"
35
48
52static char const* const transferTypeIDs[] = {
53 "item",
54 "employee",
55 "alien",
56 "aircraft"
57};
59
64
68static void TR_ClearTempCargo (void)
69{
70 tr.antimatter = 0;
71 if (tr.itemCargo != nullptr) {
72 delete tr.itemCargo;
73 tr.itemCargo = nullptr;
74 }
75 if (tr.alienCargo != nullptr) {
76 delete tr.alienCargo;
77 tr.alienCargo = nullptr;
78 }
79 for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
80 const employeeType_t emplType = (employeeType_t)i;
81 cgi->LIST_Delete(&tr.employees[emplType]);
82 }
83 cgi->LIST_Delete(&tr.aircraft);
84}
85
89static void TR_TransferStart_f (void)
90{
91 char message[1024];
93
95 cgi->Com_Printf("TR_TransferStart_f: currentTransferType is wrong!\n");
96 return;
97 }
98
99 if (TR_TransferStart(base, tr) == nullptr)
100 return;
102
103 Com_sprintf(message, sizeof(message), _("Transport mission started, cargo is being transported to %s"), tr.destBase->name);
104 MSO_CheckAddNewMessage(NT_TRANSFER_STARTED, _("Transport mission"), message, MSG_TRANSFERFINISHED);
105 cgi->UI_PopWindow(false);
106}
107
113static transferType_t TR_GetTransferType (const char* id)
114{
115 for (int i = 0; i < TRANS_TYPE_MAX; i++) {
116 if (Q_streq(transferTypeIDs[i], id))
117 return (transferType_t)i;
118 }
119 return TRANS_TYPE_INVALID;
120}
121
125static void TR_CargoList (void)
126{
127 /* reset for every new call */
128 cgi->UI_ExecuteConfunc("ui_cargolist_clear");
129
130 /* Show Antimatter */
131 if (tr.antimatter > 0) {
133 cgi->UI_ExecuteConfunc("ui_cargolist_add \"%s\" \"%s\" %d", od->id, _(od->name), tr.antimatter);
134 }
135
136 /* Show items */
137 if (tr.itemCargo != nullptr) {
138 linkedList_t* cargo = tr.itemCargo->list();
139 LIST_Foreach(cargo, itemCargo_t, item) {
140 if (item->amount > 0)
141 cgi->UI_ExecuteConfunc("ui_cargolist_add \"%s\" \"%s\" %d", item->objDef->id, _(item->objDef->name), item->amount);
142 }
143 cgi->LIST_Delete(&cargo);
144 }
145
146 /* Show employees */
147 for (int i = 0; i < MAX_EMPL; i++) {
148 const employeeType_t emplType = (employeeType_t)i;
149 switch (emplType) {
150 case EMPL_SOLDIER:
151 case EMPL_PILOT:
152 LIST_Foreach(tr.employees[emplType], Employee, employee) {
153 if (emplType == EMPL_SOLDIER) {
154 const rank_t* rank = CL_GetRankByIdx(employee->chr.score.rank);
155 cgi->UI_ExecuteConfunc("ui_cargolist_add \"ucn_%d\" \"%s %s %s\" %d", employee->chr.ucn,
156 E_GetEmployeeString((employeeType_t)emplType, 1), _(rank->shortname), employee->chr.name, 1);
157 } else {
158 cgi->UI_ExecuteConfunc("ui_cargolist_add \"ucn_%d\" \"%s %s\" %d", employee->chr.ucn,
159 E_GetEmployeeString((employeeType_t)emplType, 1), employee->chr.name, 1);
160 }
161 }
162 break;
163 case EMPL_ROBOT:
165 break;
166 case EMPL_SCIENTIST:
167 case EMPL_WORKER: {
168 int emplCount = cgi->LIST_Count(tr.employees[emplType]);
169 if (emplCount <= 0)
170 break;
171 cgi->UI_ExecuteConfunc("ui_cargolist_add \"%s\" \"%s\" %d", (emplType == EMPL_SCIENTIST) ? "scientist" : "worker",
172 E_GetEmployeeString((employeeType_t)emplType, emplCount), emplCount);
173 break;
174 }
175 default:
176 cgi->Com_Error(ERR_DROP, "TR_CargoList: Invalid employeetype in cargo");
177 }
178 }
179
180 /* Show aliens */
181 if (tr.alienCargo != nullptr) {
182 linkedList_t* cargo = tr.alienCargo->list();
183 LIST_Foreach(cargo, alienCargo_t, item) {
184 if (item->dead > 0)
185 cgi->UI_ExecuteConfunc("ui_cargolist_add \"dead_%s\" \"%s\" %d", item->teamDef->id, va(_("Corpse of %s"), _(item->teamDef->name)), item->dead);
186 if (item->alive > 0)
187 cgi->UI_ExecuteConfunc("ui_cargolist_add \"alive_%s\" \"%s\" %d", item->teamDef->id, va(_("Alive %s"), _(item->teamDef->name)), item->alive);
188 }
189 cgi->LIST_Delete(&cargo);
190 }
191
192 /* Show all aircraft */
193 LIST_Foreach(tr.aircraft, aircraft_t, aircraft) {
194 cgi->UI_ExecuteConfunc("ui_cargolist_add \"aircraft_%d\" \"%s\" %d", aircraft->idx, va(_("Aircraft %s"), aircraft->name), 1);
195 }
196}
197
203static bool TR_AircraftListSelect (const aircraft_t* aircraft)
204{
205 if (!AIR_IsAircraftInBase(aircraft)) /* Aircraft is not in base. */
206 return false;
207 if (cgi->LIST_GetPointer(tr.aircraft, aircraft)) /* Already on transfer list. */
208 return false;
209
210 return true;
211}
212
218static void TR_FillItems (const base_t* srcBase, const base_t* destBase)
219{
220 const objDef_t* od;
221
223 if (od) {
224 const int antiMatterInCargo = tr.antimatter;
225 const int antiMatterInSrcBase = B_AntimatterInBase(srcBase);
226 const int antiMatterInDstBase = B_AntimatterInBase(destBase);
227
228 if (antiMatterInCargo || antiMatterInSrcBase) {
229 cgi->UI_ExecuteConfunc("ui_translist_add \"%s\" \"%s\" %d %d %d %d %d", od->id, _(od->name),
230 antiMatterInSrcBase - antiMatterInCargo, antiMatterInDstBase, 0, antiMatterInCargo, antiMatterInSrcBase);
231 }
232 }
233 for (int i = 0; i < cgi->csi->numODs; i++) {
234 od = INVSH_GetItemByIDX(i);
235 assert(od);
237 continue;
238 const int itemCargoAmount = tr.itemCargo ? tr.itemCargo->getAmount(od) : 0;
239 const int itemInSrcBase = B_ItemInBase(od, srcBase);
240 const int itemInDstBase = B_ItemInBase(od, destBase);
241 if (itemCargoAmount || itemInSrcBase > 0) {
242 cgi->UI_ExecuteConfunc("ui_translist_add \"%s\" \"%s\" %d %d %d %d %d", od->id, _(od->name),
243 itemInSrcBase - itemCargoAmount, itemInDstBase, 0, itemCargoAmount, itemInSrcBase);
244 }
245 }
246}
247
253static void TR_FillEmployees (const base_t* srcBase, const base_t* destBase)
254{
255 for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
256 const employeeType_t emplType = (employeeType_t)i;
257 switch (emplType) {
258 case EMPL_SOLDIER:
259 case EMPL_PILOT: {
260 E_Foreach(emplType, employee) {
261 char str[128];
262
263 if (!employee->isHiredInBase(srcBase))
264 continue;
265
266 /* Skip if already on transfer list. */
267 if (cgi->LIST_GetPointer(tr.employees[emplType], (void*) employee))
268 continue;
269
270 if (emplType == EMPL_SOLDIER) {
271 const rank_t* rank = CL_GetRankByIdx(employee->chr.score.rank);
272 Com_sprintf(str, sizeof(str), "%s %s %s", E_GetEmployeeString(emplType, 1), _(rank->shortname), employee->chr.name);
273 } else {
274 Com_sprintf(str, sizeof(str), "%s %s", E_GetEmployeeString(emplType, 1), employee->chr.name);
275 }
276
277 cgi->UI_ExecuteConfunc("ui_translist_add \"ucn_%d\" \"%s\" %d %d %d %d %d", employee->chr.ucn,
278 str, -1, -1, -1, -1, -1);
279 }
280 break;
281 }
282 case EMPL_ROBOT:
284 break;
285 case EMPL_SCIENTIST:
286 case EMPL_WORKER: {
287 const int hiredSrc = E_CountHired(srcBase, emplType);
288 const int hiredDst = E_CountHired(destBase, emplType);
289 const int trCount = cgi->LIST_Count(tr.employees[emplType]);
290
291 if (hiredSrc <= 0)
292 break;
293
294 cgi->UI_ExecuteConfunc("ui_translist_add \"%s\" \"%s\" %d %d %d %d %d",
295 (emplType == EMPL_SCIENTIST) ? "scientist" : "worker", E_GetEmployeeString(emplType, hiredSrc),
296 hiredSrc - trCount, hiredDst, 0, trCount, hiredSrc);
297 break;
298 }
299 default:
300 cgi->Com_Error(ERR_DROP, "TR_CargoList: Invalid employeetype in cargo");
301 }
302 }
303}
304
310static void TR_FillAliens (const base_t* srcBase, const base_t* destBase)
311{
312 if (!srcBase->alienContainment)
313 return;
314
315 linkedList_t* list = srcBase->alienContainment->list();
316 LIST_Foreach(list, alienCargo_t, item) {
317 const int srcDead = item->dead;
318 const int srcAlive = item->alive;
319 const int dstDead = (destBase->alienContainment) ? destBase->alienContainment->getDead(item->teamDef) : 0;
320 const int dstAlive = (destBase->alienContainment) ? destBase->alienContainment->getAlive(item->teamDef) : 0;
321 const int transferDead = (tr.alienCargo) ? tr.alienCargo->getDead(item->teamDef) : 0;
322 const int transferAlive = (tr.alienCargo) ? tr.alienCargo->getAlive(item->teamDef) : 0;
323
324 if (srcDead > 0 || transferDead > 0) {
325 char str[128];
326 Com_sprintf(str, sizeof(str), _("Corpse of %s"), _(item->teamDef->name));
327 cgi->UI_ExecuteConfunc("ui_translist_add \"dead_%s\" \"%s\" %d %d %d %d %d",
328 item->teamDef->id, str, srcDead - transferDead, dstDead, 0, transferDead, srcDead);
329 }
330 if (srcAlive > 0 || transferAlive > 0) {
331 char str[128];
332 Com_sprintf(str, sizeof(str), _("Alive %s"), _(item->teamDef->name));
333 cgi->UI_ExecuteConfunc("ui_translist_add \"alive_%s\" \"%s\" %d %d %d %d %d",
334 item->teamDef->id, str, srcAlive - transferAlive, dstAlive, 0, transferAlive, srcAlive);
335 }
336 }
337 cgi->LIST_Delete(&list);
338}
339
345static void TR_FillAircraft (const base_t* srcBase, const base_t* destBase)
346{
347 AIR_ForeachFromBase(aircraft, srcBase) {
348 /* Aircraft is not in base. */
349 if (!AIR_IsAircraftInBase(aircraft))
350 continue;
351 /* Already on transfer list. */
352 if (cgi->LIST_GetPointer(tr.aircraft, aircraft))
353 continue;
354
355 cgi->UI_ExecuteConfunc("ui_translist_add \"aircraft_%d\" \"%s\" %d %d %d %d %d",
356 aircraft->idx, aircraft->name, -1, -1, -1, -1, -1);
357 }
358}
359
368static void TR_Fill (const base_t* srcBase, const base_t* destBase, transferType_t transferType)
369{
370 if (srcBase == nullptr || destBase == nullptr)
371 return;
372
373 currentTransferType = transferType;
374 /* reset for every new call */
375 cgi->UI_ExecuteConfunc("ui_translist_clear");
376 switch (transferType) {
377 case TRANS_TYPE_ITEM:
378 TR_FillItems(srcBase, destBase);
379 break;
381 TR_FillEmployees(srcBase, destBase);
382 break;
383 case TRANS_TYPE_ALIEN:
384 TR_FillAliens(srcBase, destBase);
385 break;
387 TR_FillAircraft(srcBase, destBase);
388 break;
389 default:
390 cgi->Com_Error(ERR_DROP, "invalid transfertype given: %i", transferType);
391 }
392 /* Update cargo list. */
393 TR_CargoList();
394}
395
399static void TR_Fill_f (void)
400{
402 const base_t* base = B_GetCurrentSelectedBase();
403
404 if (!tr.destBase || !base)
405 return;
406 if (cgi->Cmd_Argc() < 2)
408 else
409 type = TR_GetTransferType(cgi->Cmd_Argv(1));
411 return;
412 TR_Fill(base, tr.destBase, type);
413}
414
418static void TR_Add_f (void)
419{
421
422 if (cgi->Cmd_Argc() < 3) {
423 cgi->Com_Printf("Usage: %s <itemid> <amount>", cgi->Cmd_Argv(0));
424 return;
425 }
426
427 char itemId[MAX_VAR * 2];
428 int amount = atoi(cgi->Cmd_Argv(2));
429 Q_strncpyz(itemId, cgi->Cmd_Argv(1), sizeof(itemId));
430
431 if (Q_strstart(itemId, "aircraft_")) {
432 aircraft_t* aircraft = AIR_AircraftGetFromIDX(atoi(itemId + 9));
433 if (!aircraft)
434 return;
435 if (amount > 0) {
436 if (!TR_AircraftListSelect(aircraft))
437 return;
438
439 /* Add aircraft */
440 cgi->LIST_AddPointer(&tr.aircraft, (void*)aircraft);
441
442 /* Add pilot */
443 if (aircraft->pilot)
444 cgi->Cmd_ExecuteString("ui_trans_add ucn_%d 1", aircraft->pilot->chr.ucn);
445
446 /* Add soldiers */
447 LIST_Foreach(aircraft->acTeam, Employee, employee) {
448 cgi->Cmd_ExecuteString("ui_trans_add ucn_%d 1", employee->chr.ucn);
449 }
450 } else if (amount < 0) {
451 /* Remove aircraft */
452 cgi->LIST_Remove(&tr.aircraft, (void*)aircraft);
453
454 /* Remove pilot */
455 if (aircraft->pilot)
456 cgi->Cmd_ExecuteString("ui_trans_add ucn_%d -1", aircraft->pilot->chr.ucn);
457
458 /* Remove soldiers */
459 LIST_Foreach(aircraft->acTeam, Employee, employee) {
460 cgi->Cmd_ExecuteString("ui_trans_add ucn_%d -1", employee->chr.ucn);
461 }
462 }
463 } else if (Q_strstart(itemId, "ucn_")) {
464 Employee* employee = E_GetEmployeeFromChrUCN(atoi(itemId + 4));
465 if (!employee)
466 return;
467
468 if (amount > 0) {
469 if (!employee->isHiredInBase(base))
470 return;
471 if (cgi->LIST_GetPointer(tr.employees[employee->getType()], (void*)employee))
472 return;
473
474 /* Add employee */
475 cgi->LIST_AddPointer(&tr.employees[employee->getType()], (void*)employee);
476
477 /* Add inventory */
478 const Container* cont = nullptr;
479 while ((cont = employee->chr.inv.getNextCont(cont, true))) {
480 Item* ic = cont->getNextItem(nullptr);
481 while (ic) {
482 const Item item = *ic;
483 const objDef_t* od = item.def();
484 Item* next = ic->getNext();
485
486 if (od)
487 cgi->Cmd_ExecuteString("ui_trans_add %s 1", od->id);
488 if (item.getAmmoLeft() && od->isReloadable()) {
489 const objDef_t* ammo = item.ammoDef();
490 if (ammo)
491 cgi->Cmd_ExecuteString("ui_trans_add %s 1", ammo->id);
492 }
493 ic = next;
494 }
495 }
496 } else if (amount < 0) {
497 /* Remove employee */
498 cgi->LIST_Remove(&tr.employees[employee->getType()], (void*)employee);
499
500 /* Remove inventory */
501 const Container* cont = nullptr;
502 while ((cont = employee->chr.inv.getNextCont(cont, true))) {
503 Item* ic = cont->getNextItem(nullptr);
504 while (ic) {
505 const Item item = *ic;
506 const objDef_t* od = item.def();
507 Item* next = ic->getNext();
508
509 if (od)
510 cgi->Cmd_ExecuteString("ui_trans_add %s -1", od->id);
511 if (item.getAmmoLeft() && od->isReloadable()) {
512 const objDef_t* ammo = item.ammoDef();
513 if (ammo)
514 cgi->Cmd_ExecuteString("ui_trans_add %s -1", ammo->id);
515 }
516 ic = next;
517 }
518 }
519 }
520 } else if (Q_streq(itemId, "scientist")) {
521 if (amount > 0) {
522 E_Foreach(EMPL_SCIENTIST, employee) {
523 if (amount == 0)
524 break;
525 if (!employee->isHiredInBase(base))
526 continue;
527 /* Already on transfer list. */
528 if (cgi->LIST_GetPointer(tr.employees[EMPL_SCIENTIST], (void*)employee))
529 continue;
530 cgi->LIST_AddPointer(&tr.employees[EMPL_SCIENTIST], (void*) employee);
531 amount--;
532 }
533 } else if (amount < 0) {
534 while (!cgi->LIST_IsEmpty(tr.employees[EMPL_SCIENTIST]) && amount < 0) {
535 if (cgi->LIST_RemoveEntry(&tr.employees[EMPL_SCIENTIST], tr.employees[EMPL_SCIENTIST]))
536 amount++;
537 }
538 }
539 } else if (Q_streq(itemId, "worker")) {
540 if (amount > 0) {
541 E_Foreach(EMPL_WORKER, employee) {
542 if (amount == 0)
543 break;
544 if (!employee->isHiredInBase(base))
545 continue;
546 /* Already on transfer list. */
547 if (cgi->LIST_GetPointer(tr.employees[EMPL_WORKER], (void*)employee))
548 continue;
549 cgi->LIST_AddPointer(&tr.employees[EMPL_WORKER], (void*) employee);
550 amount--;
551 }
552 } else if (amount < 0) {
553 while (!cgi->LIST_IsEmpty(tr.employees[EMPL_WORKER]) && amount < 0) {
554 if (cgi->LIST_RemoveEntry(&tr.employees[EMPL_WORKER], tr.employees[EMPL_WORKER]))
555 amount++;
556 }
557 }
558 } else if (Q_strstart(itemId, "alive_")) {
559 if (tr.alienCargo == nullptr)
560 tr.alienCargo = new AlienCargo();
561 if (tr.alienCargo == nullptr)
562 cgi->Com_Error(ERR_DROP, "TR_Add_f: Cannot create AlienCargo object\n");
563
564 const teamDef_t* teamDef = cgi->Com_GetTeamDefinitionByID(itemId + 6);
565 if (teamDef && base->alienContainment) {
566 const int cargo = tr.alienCargo->getAlive(teamDef);
567 const int store = base->alienContainment->getAlive(teamDef);
568
569 if (amount >= 0)
570 amount = std::min(amount, store - cargo);
571 else
572 amount = std::max(amount, -cargo);
573
574 if (amount != 0)
575 tr.alienCargo->add(teamDef, amount, 0);
576 }
577 } else if (Q_strstart(itemId, "dead_")) {
578 if (tr.alienCargo == nullptr)
579 tr.alienCargo = new AlienCargo();
580 if (tr.alienCargo == nullptr)
581 cgi->Com_Error(ERR_DROP, "TR_Add_f: Cannot create AlienCargo object\n");
582
583 const teamDef_t* teamDef = cgi->Com_GetTeamDefinitionByID(itemId + 5);
584 if (teamDef && base->alienContainment) {
585 const int cargo = tr.alienCargo->getDead(teamDef);
586 const int store = base->alienContainment->getDead(teamDef);
587
588 if (amount >= 0)
589 amount = std::min(amount, store - cargo);
590 else
591 amount = std::max(amount, -cargo);
592
593 if (amount != 0)
594 tr.alienCargo->add(teamDef, 0, amount);
595 }
596 } else if (Q_streq(itemId, ANTIMATTER_ITEM_ID)) {
597 /* antimatter */
598 const int cargo = tr.antimatter;
599 const int store = B_AntimatterInBase(base);
600
601 if (amount >= 0)
602 amount = std::min(amount, store - cargo);
603 else
604 amount = std::max(amount, -cargo);
605 if (amount != 0)
606 tr.antimatter += amount;
607 } else {
608 /* items */
609 const objDef_t* od = INVSH_GetItemByID(itemId);
610 if (!od)
611 return;
613 return;
614
615 if (tr.itemCargo == nullptr)
616 tr.itemCargo = new ItemCargo();
617 const int cargo = tr.itemCargo->getAmount(od);
618 const int store = B_ItemInBase(od, base);
619 if (amount >= 0)
620 amount = std::min(amount, store - cargo);
621 else
622 amount = std::max(amount, -cargo);
623 if (amount != 0)
624 tr.itemCargo->add(od, amount, 0);
625 }
626
627 TR_Fill(base, tr.destBase, currentTransferType);
628 /* Update capacity list of destination base */
629 if (tr.destBase)
630 cgi->Cmd_ExecuteString("ui_trans_caplist %d", tr.destBase->idx);
631}
632
637static void TR_TransferListClear_f (void)
638{
640
641 if (!base)
642 return;
643
645
646 /* Update cargo list and items list. */
647 TR_CargoList();
648 TR_Fill(base, tr.destBase, currentTransferType);
649
650 /* Update capacity list of destination base */
651 if (tr.destBase)
652 cgi->Cmd_ExecuteString("ui_trans_caplist %d", tr.destBase->idx);
653}
654
661static void TR_TransferBaseSelect (base_t* srcbase, base_t* destbase)
662{
663 if (!destbase || !srcbase)
664 return;
665
666 /* Set global pointer to current selected base. */
667 tr.destBase = destbase;
668 cgi->Cvar_Set("mn_trans_base_name", "%s", destbase->name);
669 cgi->Cvar_SetValue("mn_trans_base_id", destbase->idx);
670
671 /* Update stuff-in-base list. */
672 TR_Fill(srcbase, destbase, currentTransferType);
673
674 /* Update capacity list of destination base */
675 if (tr.destBase)
676 cgi->Cmd_ExecuteString("ui_trans_caplist %d", tr.destBase->idx);
677}
678
682static void TR_InitBaseList (void)
683{
684 const base_t* currentBase = B_GetCurrentSelectedBase();
685 uiNode_t* baseList = nullptr;
686 base_t* base = nullptr;
687
688 while ((base = B_GetNext(base)) != nullptr) {
689 if (base == currentBase)
690 continue;
691
692 cgi->UI_AddOption(&baseList, va("base%i", base->idx), base->name, va("%i", base->idx));
693 }
694
695 cgi->UI_RegisterOption(OPTION_BASELIST, baseList);
696}
697
701static void TR_SelectBase_f (void)
702{
703 int baseIdx;
705 base_t* destbase;
706
707 if (cgi->Cmd_Argc() < 2) {
708 cgi->Com_Printf("Usage: %s <baseIdx>\n", cgi->Cmd_Argv(0));
709 return;
710 }
711
712 baseIdx = atoi(cgi->Cmd_Argv(1));
713 destbase = B_GetFoundedBaseByIDX(baseIdx);
714
715 TR_TransferBaseSelect(base, destbase);
716}
717
723static void TR_Init_f (void)
724{
726
728
729 /* Update destination base list */
731 /* Select first available base. */
732 tr.destBase = B_GetNext(base);
733 /* If this was the last base select the first */
734 if (!tr.destBase)
735 tr.destBase = B_GetNext(nullptr);
736 if (!tr.destBase)
737 cgi->Com_Error(ERR_DROP, "No bases! Transfer needs at least two...");
738 TR_TransferBaseSelect(base, tr.destBase);
739 /* Set up cvar used to display transferBase. */
740 if (tr.destBase) {
741 cgi->Cvar_Set("mn_trans_base_name", "%s", tr.destBase->name);
742 cgi->Cvar_SetValue("mn_trans_base_id", tr.destBase->idx);
743 } else {
744 cgi->Cvar_Set("mn_trans_base_id", "");
745 }
746
747 /* Set up cvar used with tabset */
748 cgi->Cvar_Set("mn_itemtype", "%s", transferTypeIDs[0]);
749 /* Select first available item */
750 cgi->Cmd_ExecuteString("ui_trans_fill %s", transferTypeIDs[0]);
751}
752
756static void TR_TransferClose_f (void)
757{
758 /* Unload what was loaded. */
760 /* Clear temporary cargo arrays. */
762}
763
767static void TR_List_f (void)
768{
769 int i = 0;
770
771 cgi->UI_ExecuteConfunc("tr_listclear");
772 TR_Foreach(transfer) {
773 const char* source = transfer->srcBase ? transfer->srcBase->name : "mission";
774 const DateTime remainingTime = transfer->event - ccs.date;
775 cgi->UI_ExecuteConfunc("tr_listaddtransfer %d \"%s\" \"%s\" \"%s\"", ++i, source, transfer->destBase->name, CP_SecondConvert(std::max(0, Date_DateToSeconds(remainingTime))));
776
777 /* Antimatter */
778 if (transfer->antimatter) {
779 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo", "antimatter", _("Antimatter"));
781 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo.antimatter", od->id, va("%i %s", transfer->antimatter, _(od->name)));
782 }
783 /* Items */
784 if (transfer->itemCargo != nullptr) {
785 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo", "items", _("Items"));
786 linkedList_t* cargo = transfer->itemCargo->list();
787 LIST_Foreach(cargo, itemCargo_t, item) {
788 if (item->amount <= 0)
789 continue;
790 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo.items", item->objDef->id, va("%i %s", item->amount, _(item->objDef->name)));
791 }
792 cgi->LIST_Delete(&cargo);
793 }
794 /* Employee */
795 if (transfer->hasEmployees) {
796 int j;
797 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo", "employee", _("Employee"));
798 for (j = EMPL_SOLDIER; j < MAX_EMPL; j++) {
799 const employeeType_t emplType = (employeeType_t)j;
800 TR_ForeachEmployee(employee, transfer, emplType) {
801 if (employee->getUGV()) {
803 } else {
804 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo.employee", va("ucn_%i", employee->chr.ucn), va("%s %s", E_GetEmployeeString(employee->getType(), 1), employee->chr.name));
805 }
806 }
807 }
808 }
809 /* Aliens */
810 if (transfer->alienCargo != nullptr) {
811 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo", "aliens", _("Aliens"));
812 linkedList_t* cargo = transfer->alienCargo->list();
813 LIST_Foreach(cargo, alienCargo_t, item) {
814 if (item->alive > 0)
815 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo.aliens", va("%s_alive", item->teamDef->id), va("%i %s %s", item->alive, _("alive"), _(item->teamDef->name)));
816 if (item->dead > 0)
817 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo.aliens", va("%s_dead", item->teamDef->id), va("%i %s %s", item->dead, _("dead"), _(item->teamDef->name)));
818 }
819 cgi->LIST_Delete(&cargo);
820 }
821 /* Aircraft */
822 if (!cgi->LIST_IsEmpty(transfer->aircraft)) {
823 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo", "aircraft", ngettext("Aircraft", "Aircraft", LIST_Count(transfer->aircraft)));
824
825 TR_ForeachAircraft(aircraft, transfer) {
826 cgi->UI_ExecuteConfunc("tr_listaddcargo %d \"%s\" \"%s\" \"%s\"", i, "tr_cargo.aircraft", va("craft%i", aircraft->idx), aircraft->name);
827 }
828 }
829 }
830}
831
837static void TR_CountEmployeeInListArray (linkedList_t* employeeListArray[], int capacity[])
838{
839 for (int i = EMPL_SOLDIER; i < EMPL_ROBOT; i++) {
840 capacity[CAP_EMPLOYEES] += cgi->LIST_Count(employeeListArray[i]);
841 }
842}
843
849static void TR_CountAircraftInList (linkedList_t* aircraftList, int capacity[])
850{
851 LIST_Foreach(aircraftList, aircraft_t, aircraft) {
852 capacity[AIR_GetHangarCapacityType(aircraft)]++;
853 }
854}
855
861{
862 if (cgi->Cmd_Argc() < 2) {
863 cgi->Com_Printf("Usage: %s <destinationBaseIdx>\n", cgi->Cmd_Argv(0));
864 return;
865 }
866
867 base_t* base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
868 if (!base) {
869 cgi->Com_Printf("Invalid destinationBaseIdx: %s\n", cgi->Cmd_Argv(1));
870 return;
871 }
872
873 int currentCap[MAX_CAP];
874 OBJZERO(currentCap);
875
876 /* Count capacity need of active transfers */
877 TR_Foreach(transfer) {
878 if (transfer->destBase != base)
879 continue;
880 /* - Antimatter */
881 currentCap[CAP_ANTIMATTER] += transfer->antimatter;
882 /* - Items */
883 currentCap[CAP_ITEMS] += transfer->itemCargo ? transfer->itemCargo->size() : 0;
884 /* - Employees in transit assinged to base already */
885 /* - Aliens */
886 currentCap[CAP_ALIENS] += (transfer->alienCargo) ? transfer->alienCargo->getAlive() : 0;
887 /* - Aircraft in transit are already assigned to their hangar! */
888 }
889
890 /* Count capacity need of the current transfer plan */
891 /* - Antimatter */
892 currentCap[CAP_ANTIMATTER] += tr.antimatter;
893 /* - Items */
894 currentCap[CAP_ITEMS] += tr.itemCargo ? tr.itemCargo->size() : 0;
895 /* - Employee */
896 TR_CountEmployeeInListArray(tr.employees, currentCap);
897 /* - Aliens */
898 currentCap[CAP_ALIENS] += tr.alienCargo ? tr.alienCargo->getAlive() : 0;
899 /* - Aircraft */
900 TR_CountAircraftInList(tr.aircraft, currentCap);
901
902 cgi->UI_ExecuteConfunc("ui_t_capacities_clear");
903 for (int i = 0; i < ccs.numBuildingTemplates; i++) {
904 const building_t* building = &ccs.buildingTemplates[i];
906
907 /* skip not transferable capacities */
908 if (capType == MAX_CAP || capType == CAP_LABSPACE || capType == CAP_WORKSPACE)
909 continue;
910 /* show only researched buildings' */
911 if (!RS_IsResearched_ptr(building->tech))
912 continue;
913
914 capacities_t cap = *CAP_Get(base, capType);
915 currentCap[capType] += cap.cur;
916 if (cap.max <= 0 && currentCap[capType] <= 0)
917 continue;
918
919 cgi->UI_ExecuteConfunc("ui_t_capacities_add \"%s\" \"%s\" %d %d", building->id, _(building->name), currentCap[capType], cap.max);
920 }
921}
922
923static const cmdList_t transferCallbacks[] = {
924 {"trans_list", TR_List_f, "Assembles the transferlist"},
925 {"trans_init", TR_Init_f, "Init function for Transfer menu"},
926 {"trans_close", TR_TransferClose_f, "Callback for closing Transfer Menu"},
927 {"trans_start", TR_TransferStart_f, "Starts the transfer"},
928 {"trans_emptyairstorage", TR_TransferListClear_f, "Unload everything from transfer cargo back to base"},
929 {"trans_selectbase", TR_SelectBase_f, "Callback for selecting a base"},
930 {"ui_trans_caplist", TR_DestinationCapacityList_f, "Update destination base capacity list"},
931 {"ui_trans_fill", TR_Fill_f, "Fill itemlists for transfer"},
932 {"ui_trans_add", TR_Add_f, "Add/Remove items to transfercargo"},
933 {nullptr, nullptr, nullptr}
934};
936{
937 cgi->Cmd_TableAddList(transferCallbacks);
938}
939
941{
943
944 cgi->Cmd_TableRemoveList(transferCallbacks);
945}
DateTime class definition.
Alien cargo class header.
Alien containment class header.
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
Alien cargo class.
Definition aliencargo.h:41
linkedList_t * list(void) const
Returns a copy of the cargo list.
int getAlive(const teamDef_t *team) const
Return number of alive aliens of a type in the cargo.
int getDead(const teamDef_t *team) const
Return number of dead alien bodies of a type in the cargo.
Item * getNextItem(const Item *prev) const
Class describing a point of time.
Definition DateTime.h:31
bool isHiredInBase(const base_t *const base) const
Checks whether the given employee is in the given base.
Definition cp_employee.h:94
employeeType_t getType() const
Definition cp_employee.h:99
Item cargo class.
Definition itemcargo.h:41
item instance data, with linked list capability
Definition inv_shared.h:402
const objDef_t * ammoDef(void) const
Definition inv_shared.h:460
int getAmmoLeft() const
Definition inv_shared.h:466
const objDef_t * def(void) const
Definition inv_shared.h:469
Item * getNext() const
Definition inv_shared.h:451
#define ERR_DROP
Definition common.h:211
bool AIR_IsAircraftInBase(const aircraft_t *aircraft)
Checks whether given aircraft is in its homebase.
baseCapacities_t AIR_GetHangarCapacityType(const aircraft_t *aircraft)
Returns capacity type needed for an aircraft.
aircraft_t * AIR_AircraftGetFromIDX(int aircraftIdx)
Returns aircraft for a given global index.
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
baseCapacities_t B_GetCapacityFromBuildingType(buildingType_t type)
Get the capacity associated to a building type.
Definition cp_base.cpp:416
base_t * B_GetFoundedBaseByIDX(int baseIdx)
Array bound check for the base index.
Definition cp_base.cpp:326
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition cp_base.cpp:286
bool B_ItemIsStoredInBaseStorage(const objDef_t *obj)
Check if an item is stored in storage.
Definition cp_base.cpp:2560
base_t * B_GetCurrentSelectedBase(void)
returns the currently selected base
Definition cp_base.cpp:1578
int B_AntimatterInBase(const base_t *base)
returns the amount of antimatter stored in a base
Definition cp_base.cpp:2613
int B_ItemInBase(const objDef_t *item, const base_t *base)
Check if the item has been collected (i.e it is in the storage) in the given base.
Definition cp_base.cpp:2133
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
baseCapacities_t
All possible capacities in base.
Definition cp_capacity.h:27
@ CAP_ANTIMATTER
Definition cp_capacity.h:35
@ CAP_WORKSPACE
Definition cp_capacity.h:34
@ CAP_ITEMS
Definition cp_capacity.h:32
@ MAX_CAP
Definition cp_capacity.h:37
@ CAP_LABSPACE
Definition cp_capacity.h:33
@ CAP_EMPLOYEES
Definition cp_capacity.h:31
@ CAP_ALIENS
Definition cp_capacity.h:28
#define CAP_Get(base, capacity)
Capacity macros.
Definition cp_capacity.h:50
Employee * E_GetEmployeeFromChrUCN(int uniqueCharacterNumber)
Searches all employee for the ucn (character id).
const char * E_GetEmployeeString(employeeType_t type, int n)
Convert employeeType_t to translated string.
int E_CountHired(const base_t *const base, employeeType_t type)
Counts hired employees of a given type in a given base.
employeeType_t
The types of employees.
Definition cp_employee.h:30
@ EMPL_SOLDIER
Definition cp_employee.h:31
@ MAX_EMPL
Definition cp_employee.h:36
@ EMPL_ROBOT
Definition cp_employee.h:35
@ EMPL_PILOT
Definition cp_employee.h:34
@ EMPL_WORKER
Definition cp_employee.h:33
@ EMPL_SCIENTIST
Definition cp_employee.h:32
#define E_Foreach(employeeType, var)
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
@ MSG_TRANSFERFINISHED
Definition cp_messages.h:44
rank_t * CL_GetRankByIdx(const int index)
Returns a rank at an index.
Definition cp_rank.cpp:50
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
#define ANTIMATTER_ITEM_ID
Definition cp_research.h:37
const char * CP_SecondConvert(int second)
Converts a number of second into a char to display.
Definition cp_time.cpp:57
int Date_DateToSeconds(const DateTime &date)
Convert a date to seconds.
Definition cp_time.cpp:228
Campaign geoscape time header.
transfer_t * TR_TransferStart(base_t *srcBase, transfer_t &transData)
Starts a transfer.
Header file for Transfer stuff.
#define TR_ForeachEmployee(var, transfer, employeeType)
Definition cp_transfer.h:49
#define TR_Foreach(var)
Definition cp_transfer.h:48
#define TR_ForeachAircraft(var, transfer)
Definition cp_transfer.h:50
static void TR_Add_f(void)
Callback handles adding/removing items to transfercargo.
static char const *const transferTypeIDs[]
transfer typeID strings
static void TR_TransferListClear_f(void)
Unload everything from transfer cargo back to base.
static const cmdList_t transferCallbacks[]
static void TR_FillAircraft(const base_t *srcBase, const base_t *destBase)
Add aircraft to the transfer storages list.
void TR_InitCallbacks(void)
static void TR_TransferClose_f(void)
Closes Transfer Menu and resets temp arrays.
static void TR_TransferBaseSelect(base_t *srcbase, base_t *destbase)
Callback for base list click.
static void TR_SelectBase_f(void)
Callback to select destination base.
transferType_t
transfer types
@ TRANS_TYPE_INVALID
@ TRANS_TYPE_EMPLOYEE
@ TRANS_TYPE_AIRCRAFT
static void TR_CountAircraftInList(linkedList_t *aircraftList, int capacity[])
Count capacity need of aircraft in lists.
static void TR_Fill(const base_t *srcBase, const base_t *destBase, transferType_t transferType)
Fills the items-in-base list with stuff available for transfer.
static bool TR_AircraftListSelect(const aircraft_t *aircraft)
Check if an aircraft should be displayed for transfer.
static void TR_CountEmployeeInListArray(linkedList_t *employeeListArray[], int capacity[])
Count capacity need of employee in array of lists.
static void TR_Fill_f(void)
Callback for filling list with stuff available for transfer.
static transferType_t currentTransferType
static void TR_TransferStart_f(void)
Starts the transfer.
void TR_ShutdownCallbacks(void)
static void TR_FillItems(const base_t *srcBase, const base_t *destBase)
Add items to the transfer storages list.
static void TR_CargoList(void)
Display cargo list.
static void TR_FillEmployees(const base_t *srcBase, const base_t *destBase)
Add employees to the transfer storages list.
static transferType_t TR_GetTransferType(const char *id)
Returns the transfer type.
static void TR_DestinationCapacityList_f(void)
Callback for assemble destination base capacity list.
static void TR_Init_f(void)
Transfer menu init function.
static void TR_List_f(void)
Assembles the list of transfers for the popup.
static transfer_t tr
static void TR_InitBaseList(void)
Fills the optionlist with available bases to transfer to.
static void TR_FillAliens(const base_t *srcBase, const base_t *destBase)
Add aliens to the transfer storages list.
static void TR_ClearTempCargo(void)
Clear temporary cargo arrays.
Header file for menu related console command callbacks.
#define ngettext(x, y, cnt)
Definition g_local.h:40
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
const objDef_t * INVSH_GetItemByID(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn't found.
Item cargo class header.
int LIST_Count(const linkedList_t *list)
Definition list.cpp:344
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it's safe to delete the returned entry from the list while looping over ...
Definition list.h:41
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
#define Q_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
#define MAX_VAR
Definition shared.h:36
#define lengthof(x)
Definition shared.h:105
#define CASSERT(x)
Definition shared.h:107
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
An aircraft with all it's data.
alien cargo entry
Definition aliencargo.h:32
A base with all it's data.
Definition cp_base.h:84
class AlienContainment * alienContainment
Definition cp_base.h:108
int idx
Definition cp_base.h:85
char name[MAX_VAR]
Definition cp_base.h:86
A building with all it's data.
Definition cp_building.h:73
char * name
Definition cp_building.h:79
buildingType_t buildingType
const char * id
Definition cp_building.h:78
struct technology_s * tech
Store capacities in base.
Definition cp_capacity.h:41
item cargo entry
Definition itemcargo.h:32
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
bool isReloadable() const
Definition inv_shared.h:352
const char * id
Definition inv_shared.h:268
const char * name
Definition inv_shared.h:267
Describes a rank that a recruit can gain.
Definition cp_rank.h:29
const char * shortname
Definition cp_rank.h:32
Transfer information (they are being stored in ccs.transfers).
Definition cp_transfer.h:33
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
@ OPTION_BASELIST
Definition ui_dataids.h:83