UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cp_transfer_callbacks.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23 
24 #include "cp_transfer_callbacks.h"
25 #include "../../cl_shared.h"
26 #include "cp_campaign.h"
27 #include "cp_capacity.h"
28 #include "cp_transfer.h"
29 #include "cp_popup.h"
30 #include "cp_time.h"
31 #include "aliencargo.h"
32 #include "aliencontainment.h"
33 #include "itemcargo.h"
34 
38 typedef enum {
44 
47 
51 static char const* const transferTypeIDs[] = {
52  "item",
53  "employee",
54  "alien",
55  "aircraft"
56 };
58 
60 static transfer_t tr;
63 
67 static void TR_ClearTempCargo (void)
68 {
69  tr.antimatter = 0;
70  if (tr.itemCargo != nullptr) {
71  delete tr.itemCargo;
72  tr.itemCargo = nullptr;
73  }
74  if (tr.alienCargo != nullptr) {
75  delete tr.alienCargo;
76  tr.alienCargo = nullptr;
77  }
78  for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
79  const employeeType_t emplType = (employeeType_t)i;
80  cgi->LIST_Delete(&tr.employees[emplType]);
81  }
82  cgi->LIST_Delete(&tr.aircraft);
83 }
84 
88 static void TR_TransferStart_f (void)
89 {
90  char message[1024];
92 
93  if (currentTransferType == TRANS_TYPE_INVALID) {
94  cgi->Com_Printf("TR_TransferStart_f: currentTransferType is wrong!\n");
95  return;
96  }
97 
98  if (TR_TransferStart(base, tr) == nullptr)
99  return;
101 
102  Com_sprintf(message, sizeof(message), _("Transport mission started, cargo is being transported to %s"), tr.destBase->name);
103  MSO_CheckAddNewMessage(NT_TRANSFER_STARTED, _("Transport mission"), message, MSG_TRANSFERFINISHED);
104  cgi->UI_PopWindow(false);
105 }
106 
112 static transferType_t TR_GetTransferType (const char* id)
113 {
114  for (int i = 0; i < TRANS_TYPE_MAX; i++) {
115  if (Q_streq(transferTypeIDs[i], id))
116  return (transferType_t)i;
117  }
118  return TRANS_TYPE_INVALID;
119 }
120 
124 static void TR_CargoList (void)
125 {
126  /* reset for every new call */
127  cgi->UI_ExecuteConfunc("ui_cargolist_clear");
128 
129  /* Show Antimatter */
130  if (tr.antimatter > 0) {
132  cgi->UI_ExecuteConfunc("ui_cargolist_add \"%s\" \"%s\" %d", od->id, _(od->name), tr.antimatter);
133  }
134 
135  /* Show items */
136  if (tr.itemCargo != nullptr) {
137  linkedList_t* cargo = tr.itemCargo->list();
138  LIST_Foreach(cargo, itemCargo_t, item) {
139  if (item->amount > 0)
140  cgi->UI_ExecuteConfunc("ui_cargolist_add \"%s\" \"%s\" %d", item->objDef->id, _(item->objDef->name), item->amount);
141  }
142  cgi->LIST_Delete(&cargo);
143  }
144 
145  /* Show employees */
146  for (int i = 0; i < MAX_EMPL; i++) {
147  const employeeType_t emplType = (employeeType_t)i;
148  switch (emplType) {
149  case EMPL_SOLDIER:
150  case EMPL_PILOT:
151  LIST_Foreach(tr.employees[emplType], Employee, employee) {
152  if (emplType == EMPL_SOLDIER) {
153  const rank_t* rank = CL_GetRankByIdx(employee->chr.score.rank);
154  cgi->UI_ExecuteConfunc("ui_cargolist_add \"ucn_%d\" \"%s %s %s\" %d", employee->chr.ucn,
155  E_GetEmployeeString((employeeType_t)emplType, 1), _(rank->shortname), employee->chr.name, 1);
156  } else {
157  cgi->UI_ExecuteConfunc("ui_cargolist_add \"ucn_%d\" \"%s %s\" %d", employee->chr.ucn,
158  E_GetEmployeeString((employeeType_t)emplType, 1), employee->chr.name, 1);
159  }
160  }
161  break;
162  case EMPL_ROBOT:
164  break;
165  case EMPL_SCIENTIST:
166  case EMPL_WORKER: {
167  int emplCount = cgi->LIST_Count(tr.employees[emplType]);
168  if (emplCount <= 0)
169  break;
170  cgi->UI_ExecuteConfunc("ui_cargolist_add \"%s\" \"%s\" %d", (emplType == EMPL_SCIENTIST) ? "scientist" : "worker",
171  E_GetEmployeeString((employeeType_t)emplType, emplCount), emplCount);
172  break;
173  }
174  default:
175  cgi->Com_Error(ERR_DROP, "TR_CargoList: Invalid employeetype in cargo");
176  }
177  }
178 
179  /* Show aliens */
180  if (tr.alienCargo != nullptr) {
182  LIST_Foreach(cargo, alienCargo_t, item) {
183  if (item->dead > 0)
184  cgi->UI_ExecuteConfunc("ui_cargolist_add \"dead_%s\" \"%s\" %d", item->teamDef->id, va(_("Corpse of %s"), _(item->teamDef->name)), item->dead);
185  if (item->alive > 0)
186  cgi->UI_ExecuteConfunc("ui_cargolist_add \"alive_%s\" \"%s\" %d", item->teamDef->id, va(_("Alive %s"), _(item->teamDef->name)), item->alive);
187  }
188  cgi->LIST_Delete(&cargo);
189  }
190 
191  /* Show all aircraft */
192  LIST_Foreach(tr.aircraft, aircraft_t, aircraft) {
193  cgi->UI_ExecuteConfunc("ui_cargolist_add \"aircraft_%d\" \"%s\" %d", aircraft->idx, va(_("Aircraft %s"), aircraft->name), 1);
194  }
195 }
196 
202 static bool TR_AircraftListSelect (const aircraft_t* aircraft)
203 {
204  if (!AIR_IsAircraftInBase(aircraft)) /* Aircraft is not in base. */
205  return false;
206  if (cgi->LIST_GetPointer(tr.aircraft, aircraft)) /* Already on transfer list. */
207  return false;
208 
209  return true;
210 }
211 
217 static void TR_FillItems (const base_t* srcBase, const base_t* destBase)
218 {
219  const objDef_t* od;
220 
222  if (od) {
223  const int antiMatterInCargo = tr.antimatter;
224  const int antiMatterInSrcBase = B_AntimatterInBase(srcBase);
225  const int antiMatterInDstBase = B_AntimatterInBase(destBase);
226 
227  if (antiMatterInCargo || antiMatterInSrcBase) {
228  cgi->UI_ExecuteConfunc("ui_translist_add \"%s\" \"%s\" %d %d %d %d %d", od->id, _(od->name),
229  antiMatterInSrcBase - antiMatterInCargo, antiMatterInDstBase, 0, antiMatterInCargo, antiMatterInSrcBase);
230  }
231  }
232  for (int i = 0; i < cgi->csi->numODs; i++) {
233  od = INVSH_GetItemByIDX(i);
234  assert(od);
236  continue;
237  const int itemCargoAmount = tr.itemCargo ? tr.itemCargo->getAmount(od) : 0;
238  const int itemInSrcBase = B_ItemInBase(od, srcBase);
239  const int itemInDstBase = B_ItemInBase(od, destBase);
240  if (itemCargoAmount || itemInSrcBase > 0) {
241  cgi->UI_ExecuteConfunc("ui_translist_add \"%s\" \"%s\" %d %d %d %d %d", od->id, _(od->name),
242  itemInSrcBase - itemCargoAmount, itemInDstBase, 0, itemCargoAmount, itemInSrcBase);
243  }
244  }
245 }
246 
252 static void TR_FillEmployees (const base_t* srcBase, const base_t* destBase)
253 {
254  for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
255  const employeeType_t emplType = (employeeType_t)i;
256  switch (emplType) {
257  case EMPL_SOLDIER:
258  case EMPL_PILOT: {
259  E_Foreach(emplType, employee) {
260  char str[128];
261 
262  if (!employee->isHiredInBase(srcBase))
263  continue;
264 
265  /* Skip if already on transfer list. */
266  if (cgi->LIST_GetPointer(tr.employees[emplType], (void*) employee))
267  continue;
268 
269  if (emplType == EMPL_SOLDIER) {
270  const rank_t* rank = CL_GetRankByIdx(employee->chr.score.rank);
271  Com_sprintf(str, sizeof(str), "%s %s %s", E_GetEmployeeString(emplType, 1), _(rank->shortname), employee->chr.name);
272  } else {
273  Com_sprintf(str, sizeof(str), "%s %s", E_GetEmployeeString(emplType, 1), employee->chr.name);
274  }
275 
276  cgi->UI_ExecuteConfunc("ui_translist_add \"ucn_%d\" \"%s\" %d %d %d %d %d", employee->chr.ucn,
277  str, -1, -1, -1, -1, -1);
278  }
279  break;
280  }
281  case EMPL_ROBOT:
283  break;
284  case EMPL_SCIENTIST:
285  case EMPL_WORKER: {
286  const int hiredSrc = E_CountHired(srcBase, emplType);
287  const int hiredDst = E_CountHired(destBase, emplType);
288  const int trCount = cgi->LIST_Count(tr.employees[emplType]);
289 
290  if (hiredSrc <= 0)
291  break;
292 
293  cgi->UI_ExecuteConfunc("ui_translist_add \"%s\" \"%s\" %d %d %d %d %d",
294  (emplType == EMPL_SCIENTIST) ? "scientist" : "worker", E_GetEmployeeString(emplType, hiredSrc),
295  hiredSrc - trCount, hiredDst, 0, trCount, hiredSrc);
296  break;
297  }
298  default:
299  cgi->Com_Error(ERR_DROP, "TR_CargoList: Invalid employeetype in cargo");
300  }
301  }
302 }
303 
309 static void TR_FillAliens (const base_t* srcBase, const base_t* destBase)
310 {
311  if (!srcBase->alienContainment)
312  return;
313 
314  linkedList_t* list = srcBase->alienContainment->list();
315  LIST_Foreach(list, alienCargo_t, item) {
316  const int srcDead = item->dead;
317  const int srcAlive = item->alive;
318  const int dstDead = (destBase->alienContainment) ? destBase->alienContainment->getDead(item->teamDef) : 0;
319  const int dstAlive = (destBase->alienContainment) ? destBase->alienContainment->getAlive(item->teamDef) : 0;
320  const int transferDead = (tr.alienCargo) ? tr.alienCargo->getDead(item->teamDef) : 0;
321  const int transferAlive = (tr.alienCargo) ? tr.alienCargo->getAlive(item->teamDef) : 0;
322 
323  if (srcDead > 0 || transferDead > 0) {
324  char str[128];
325  Com_sprintf(str, sizeof(str), _("Corpse of %s"), _(item->teamDef->name));
326  cgi->UI_ExecuteConfunc("ui_translist_add \"dead_%s\" \"%s\" %d %d %d %d %d",
327  item->teamDef->id, str, srcDead - transferDead, dstDead, 0, transferDead, srcDead);
328  }
329  if (srcAlive > 0 || transferAlive > 0) {
330  char str[128];
331  Com_sprintf(str, sizeof(str), _("Alive %s"), _(item->teamDef->name));
332  cgi->UI_ExecuteConfunc("ui_translist_add \"alive_%s\" \"%s\" %d %d %d %d %d",
333  item->teamDef->id, str, srcAlive - transferAlive, dstAlive, 0, transferAlive, srcAlive);
334  }
335  }
336  cgi->LIST_Delete(&list);
337 }
338 
344 static void TR_FillAircraft (const base_t* srcBase, const base_t* destBase)
345 {
346  AIR_ForeachFromBase(aircraft, srcBase) {
347  /* Aircraft is not in base. */
348  if (!AIR_IsAircraftInBase(aircraft))
349  continue;
350  /* Already on transfer list. */
351  if (cgi->LIST_GetPointer(tr.aircraft, aircraft))
352  continue;
353 
354  cgi->UI_ExecuteConfunc("ui_translist_add \"aircraft_%d\" \"%s\" %d %d %d %d %d",
355  aircraft->idx, aircraft->name, -1, -1, -1, -1, -1);
356  }
357 }
358 
367 static void TR_Fill (const base_t* srcBase, const base_t* destBase, transferType_t transferType)
368 {
369  if (srcBase == nullptr || destBase == nullptr)
370  return;
371 
372  currentTransferType = transferType;
373  /* reset for every new call */
374  cgi->UI_ExecuteConfunc("ui_translist_clear");
375  switch (transferType) {
376  case TRANS_TYPE_ITEM:
377  TR_FillItems(srcBase, destBase);
378  break;
379  case TRANS_TYPE_EMPLOYEE:
380  TR_FillEmployees(srcBase, destBase);
381  break;
382  case TRANS_TYPE_ALIEN:
383  TR_FillAliens(srcBase, destBase);
384  break;
385  case TRANS_TYPE_AIRCRAFT:
386  TR_FillAircraft(srcBase, destBase);
387  break;
388  default:
389  cgi->Com_Error(ERR_DROP, "invalid transfertype given: %i", transferType);
390  }
391  /* Update cargo list. */
392  TR_CargoList();
393 }
394 
398 static void TR_Fill_f (void)
399 {
401  const base_t* base = B_GetCurrentSelectedBase();
402 
403  if (!tr.destBase || !base)
404  return;
405  if (cgi->Cmd_Argc() < 2)
406  type = currentTransferType;
407  else
408  type = TR_GetTransferType(cgi->Cmd_Argv(1));
409  if (type == TRANS_TYPE_INVALID)
410  return;
411  TR_Fill(base, tr.destBase, type);
412 }
413 
417 static void TR_Add_f (void)
418 {
420 
421  if (cgi->Cmd_Argc() < 3) {
422  cgi->Com_Printf("Usage: %s <itemid> <amount>", cgi->Cmd_Argv(0));
423  return;
424  }
425 
426  char itemId[MAX_VAR * 2];
427  int amount = atoi(cgi->Cmd_Argv(2));
428  Q_strncpyz(itemId, cgi->Cmd_Argv(1), sizeof(itemId));
429 
430  if (Q_strstart(itemId, "aircraft_")) {
431  aircraft_t* aircraft = AIR_AircraftGetFromIDX(atoi(itemId + 9));
432  if (!aircraft)
433  return;
434  if (amount > 0) {
435  if (!TR_AircraftListSelect(aircraft))
436  return;
437 
438  /* Add aircraft */
439  cgi->LIST_AddPointer(&tr.aircraft, (void*)aircraft);
440 
441  /* Add pilot */
442  if (aircraft->pilot)
443  cgi->Cmd_ExecuteString("ui_trans_add ucn_%d 1", aircraft->pilot->chr.ucn);
444 
445  /* Add soldiers */
446  LIST_Foreach(aircraft->acTeam, Employee, employee) {
447  cgi->Cmd_ExecuteString("ui_trans_add ucn_%d 1", employee->chr.ucn);
448  }
449  } else if (amount < 0) {
450  /* Remove aircraft */
451  cgi->LIST_Remove(&tr.aircraft, (void*)aircraft);
452 
453  /* Remove pilot */
454  if (aircraft->pilot)
455  cgi->Cmd_ExecuteString("ui_trans_add ucn_%d -1", aircraft->pilot->chr.ucn);
456 
457  /* Remove soldiers */
458  LIST_Foreach(aircraft->acTeam, Employee, employee) {
459  cgi->Cmd_ExecuteString("ui_trans_add ucn_%d -1", employee->chr.ucn);
460  }
461  }
462  } else if (Q_strstart(itemId, "ucn_")) {
463  Employee* employee = E_GetEmployeeFromChrUCN(atoi(itemId + 4));
464  if (!employee)
465  return;
466 
467  if (amount > 0) {
468  if (!employee->isHiredInBase(base))
469  return;
470  if (cgi->LIST_GetPointer(tr.employees[employee->getType()], (void*)employee))
471  return;
472 
473  /* Add employee */
474  cgi->LIST_AddPointer(&tr.employees[employee->getType()], (void*)employee);
475 
476  /* Add inventory */
477  const Container* cont = nullptr;
478  while ((cont = employee->chr.inv.getNextCont(cont, true))) {
479  Item* ic = cont->getNextItem(nullptr);
480  while (ic) {
481  const Item item = *ic;
482  const objDef_t* od = item.def();
483  Item* next = ic->getNext();
484 
485  if (od)
486  cgi->Cmd_ExecuteString("ui_trans_add %s 1", od->id);
487  if (item.getAmmoLeft() && od->isReloadable()) {
488  const objDef_t* ammo = item.ammoDef();
489  if (ammo)
490  cgi->Cmd_ExecuteString("ui_trans_add %s 1", ammo->id);
491  }
492  ic = next;
493  }
494  }
495  } else if (amount < 0) {
496  /* Remove employee */
497  cgi->LIST_Remove(&tr.employees[employee->getType()], (void*)employee);
498 
499  /* Remove inventory */
500  const Container* cont = nullptr;
501  while ((cont = employee->chr.inv.getNextCont(cont, true))) {
502  Item* ic = cont->getNextItem(nullptr);
503  while (ic) {
504  const Item item = *ic;
505  const objDef_t* od = item.def();
506  Item* next = ic->getNext();
507 
508  if (od)
509  cgi->Cmd_ExecuteString("ui_trans_add %s -1", od->id);
510  if (item.getAmmoLeft() && od->isReloadable()) {
511  const objDef_t* ammo = item.ammoDef();
512  if (ammo)
513  cgi->Cmd_ExecuteString("ui_trans_add %s -1", ammo->id);
514  }
515  ic = next;
516  }
517  }
518  }
519  } else if (Q_streq(itemId, "scientist")) {
520  if (amount > 0) {
521  E_Foreach(EMPL_SCIENTIST, employee) {
522  if (amount == 0)
523  break;
524  if (!employee->isHiredInBase(base))
525  continue;
526  /* Already on transfer list. */
527  if (cgi->LIST_GetPointer(tr.employees[EMPL_SCIENTIST], (void*)employee))
528  continue;
529  cgi->LIST_AddPointer(&tr.employees[EMPL_SCIENTIST], (void*) employee);
530  amount--;
531  }
532  } else if (amount < 0) {
533  while (!cgi->LIST_IsEmpty(tr.employees[EMPL_SCIENTIST]) && amount < 0) {
534  if (cgi->LIST_RemoveEntry(&tr.employees[EMPL_SCIENTIST], tr.employees[EMPL_SCIENTIST]))
535  amount++;
536  }
537  }
538  } else if (Q_streq(itemId, "worker")) {
539  if (amount > 0) {
540  E_Foreach(EMPL_WORKER, employee) {
541  if (amount == 0)
542  break;
543  if (!employee->isHiredInBase(base))
544  continue;
545  /* Already on transfer list. */
546  if (cgi->LIST_GetPointer(tr.employees[EMPL_WORKER], (void*)employee))
547  continue;
548  cgi->LIST_AddPointer(&tr.employees[EMPL_WORKER], (void*) employee);
549  amount--;
550  }
551  } else if (amount < 0) {
552  while (!cgi->LIST_IsEmpty(tr.employees[EMPL_WORKER]) && amount < 0) {
553  if (cgi->LIST_RemoveEntry(&tr.employees[EMPL_WORKER], tr.employees[EMPL_WORKER]))
554  amount++;
555  }
556  }
557  } else if (Q_strstart(itemId, "alive_")) {
558  if (tr.alienCargo == nullptr)
559  tr.alienCargo = new AlienCargo();
560  if (tr.alienCargo == nullptr)
561  cgi->Com_Error(ERR_DROP, "TR_Add_f: Cannot create AlienCargo object\n");
562 
563  const teamDef_t* teamDef = cgi->Com_GetTeamDefinitionByID(itemId + 6);
564  if (teamDef && base->alienContainment) {
565  const int cargo = tr.alienCargo->getAlive(teamDef);
566  const int store = base->alienContainment->getAlive(teamDef);
567 
568  if (amount >= 0)
569  amount = std::min(amount, store - cargo);
570  else
571  amount = std::max(amount, -cargo);
572 
573  if (amount != 0)
574  tr.alienCargo->add(teamDef, amount, 0);
575  }
576  } else if (Q_strstart(itemId, "dead_")) {
577  if (tr.alienCargo == nullptr)
578  tr.alienCargo = new AlienCargo();
579  if (tr.alienCargo == nullptr)
580  cgi->Com_Error(ERR_DROP, "TR_Add_f: Cannot create AlienCargo object\n");
581 
582  const teamDef_t* teamDef = cgi->Com_GetTeamDefinitionByID(itemId + 5);
583  if (teamDef && base->alienContainment) {
584  const int cargo = tr.alienCargo->getDead(teamDef);
585  const int store = base->alienContainment->getDead(teamDef);
586 
587  if (amount >= 0)
588  amount = std::min(amount, store - cargo);
589  else
590  amount = std::max(amount, -cargo);
591 
592  if (amount != 0)
593  tr.alienCargo->add(teamDef, 0, amount);
594  }
595  } else if (Q_streq(itemId, ANTIMATTER_ITEM_ID)) {
596  /* antimatter */
597  const int cargo = tr.antimatter;
598  const int store = B_AntimatterInBase(base);
599 
600  if (amount >= 0)
601  amount = std::min(amount, store - cargo);
602  else
603  amount = std::max(amount, -cargo);
604  if (amount != 0)
605  tr.antimatter += amount;
606  } else {
607  /* items */
608  const objDef_t* od = INVSH_GetItemByID(itemId);
609  if (!od)
610  return;
612  return;
613 
614  if (tr.itemCargo == nullptr)
615  tr.itemCargo = new ItemCargo();
616  const int cargo = tr.itemCargo->getAmount(od);
617  const int store = B_ItemInBase(od, base);
618  if (amount >= 0)
619  amount = std::min(amount, store - cargo);
620  else
621  amount = std::max(amount, -cargo);
622  if (amount != 0)
623  tr.itemCargo->add(od, amount, 0);
624  }
625 
626  TR_Fill(base, tr.destBase, currentTransferType);
627  /* Update capacity list of destination base */
628  if (tr.destBase)
629  cgi->Cmd_ExecuteString("ui_trans_caplist %d", tr.destBase->idx);
630 }
631 
636 static void TR_TransferListClear_f (void)
637 {
639 
640  if (!base)
641  return;
642 
644 
645  /* Update cargo list and items list. */
646  TR_CargoList();
647  TR_Fill(base, tr.destBase, currentTransferType);
648 
649  /* Update capacity list of destination base */
650  if (tr.destBase)
651  cgi->Cmd_ExecuteString("ui_trans_caplist %d", tr.destBase->idx);
652 }
653 
660 static void TR_TransferBaseSelect (base_t* srcbase, base_t* destbase)
661 {
662  if (!destbase || !srcbase)
663  return;
664 
665  /* Set global pointer to current selected base. */
666  tr.destBase = destbase;
667  cgi->Cvar_Set("mn_trans_base_name", "%s", destbase->name);
668  cgi->Cvar_SetValue("mn_trans_base_id", destbase->idx);
669 
670  /* Update stuff-in-base list. */
671  TR_Fill(srcbase, destbase, currentTransferType);
672 
673  /* Update capacity list of destination base */
674  if (tr.destBase)
675  cgi->Cmd_ExecuteString("ui_trans_caplist %d", tr.destBase->idx);
676 }
677 
681 static void TR_InitBaseList (void)
682 {
683  const base_t* currentBase = B_GetCurrentSelectedBase();
684  uiNode_t* baseList = nullptr;
685  base_t* base = nullptr;
686 
687  while ((base = B_GetNext(base)) != nullptr) {
688  if (base == currentBase)
689  continue;
690 
691  cgi->UI_AddOption(&baseList, va("base%i", base->idx), base->name, va("%i", base->idx));
692  }
693 
694  cgi->UI_RegisterOption(OPTION_BASELIST, baseList);
695 }
696 
700 static void TR_SelectBase_f (void)
701 {
702  int baseIdx;
704  base_t* destbase;
705 
706  if (cgi->Cmd_Argc() < 2) {
707  cgi->Com_Printf("Usage: %s <baseIdx>\n", cgi->Cmd_Argv(0));
708  return;
709  }
710 
711  baseIdx = atoi(cgi->Cmd_Argv(1));
712  destbase = B_GetFoundedBaseByIDX(baseIdx);
713 
714  TR_TransferBaseSelect(base, destbase);
715 }
716 
722 static void TR_Init_f (void)
723 {
725 
727 
728  /* Update destination base list */
729  TR_InitBaseList();
730  /* Select first available base. */
731  tr.destBase = B_GetNext(base);
732  /* If this was the last base select the first */
733  if (!tr.destBase)
734  tr.destBase = B_GetNext(nullptr);
735  if (!tr.destBase)
736  cgi->Com_Error(ERR_DROP, "No bases! Transfer needs at least two...");
738  /* Set up cvar used to display transferBase. */
739  if (tr.destBase) {
740  cgi->Cvar_Set("mn_trans_base_name", "%s", tr.destBase->name);
741  cgi->Cvar_SetValue("mn_trans_base_id", tr.destBase->idx);
742  } else {
743  cgi->Cvar_Set("mn_trans_base_id", "");
744  }
745 
746  /* Set up cvar used with tabset */
747  cgi->Cvar_Set("mn_itemtype", "%s", transferTypeIDs[0]);
748  /* Select first available item */
749  cgi->Cmd_ExecuteString("ui_trans_fill %s", transferTypeIDs[0]);
750 }
751 
755 static void TR_TransferClose_f (void)
756 {
757  /* Unload what was loaded. */
759  /* Clear temporary cargo arrays. */
761 }
762 
766 static void TR_List_f (void)
767 {
768  int i = 0;
769 
770  cgi->UI_ExecuteConfunc("tr_listclear");
771  TR_Foreach(transfer) {
772  const char* source = transfer->srcBase ? transfer->srcBase->name : "mission";
773  date_t time = Date_Substract(transfer->event, ccs.date);
774 
775  cgi->UI_ExecuteConfunc("tr_listaddtransfer %d \"%s\" \"%s\" \"%s\"", ++i, source, transfer->destBase->name, CP_SecondConvert(Date_DateToSeconds(&time)));
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", _("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 
837 static 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 
849 static 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 
923 static 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 };
935 void TR_InitCallbacks (void)
936 {
937  cgi->Cmd_TableAddList(transferCallbacks);
938 }
939 
941 {
943 
944  cgi->Cmd_TableRemoveList(transferCallbacks);
945 }
static void TR_Init_f(void)
Transfer menu init function.
static void TR_CargoList(void)
Display cargo list.
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:2134
const char * id
Definition: cp_building.h:78
bool AIR_IsAircraftInBase(const aircraft_t *aircraft)
Checks whether given aircraft is in its homebase.
virtual bool add(const objDef_t *od, int amount, int looseAmount)
Add items to the cargo.
Definition: itemcargo.cpp:39
A building with all it's data.
Definition: cp_building.h:73
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...
virtual bool add(const teamDef_t *team, int alive, int dead)
Add aliens to the cargo by teamDef.
Definition: aliencargo.cpp:38
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
const objDef_t * INVSH_GetItemByID(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn't found.
Definition: inv_shared.cpp:282
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
Describes a rank that a recruit can gain.
Definition: cp_rank.h:29
Header file for menu related console command callbacks.
int antimatter
Definition: cp_transfer.h:36
static void TR_Add_f(void)
Callback handles adding/removing items to transfercargo.
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
int getAmmoLeft() const
Definition: inv_shared.h:466
#define E_Foreach(employeeType, var)
Definition: cp_employee.h:122
#define _(String)
Definition: cl_shared.h:43
static void TR_List_f(void)
Assembles the list of transfers for the popup.
int numBuildingTemplates
Definition: cp_campaign.h:339
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
struct technology_s * tech
Definition: cp_building.h:111
char name[MAX_VAR]
Definition: cp_base.h:86
static void TR_FillItems(const base_t *srcBase, const base_t *destBase)
Add items to the transfer storages list.
#define CAP_Get(base, capacity)
Capacity macros.
Definition: cp_capacity.h:50
csi_t * csi
Definition: cgame.h:100
linkedList_t * list(void) const
Returns a copy of the cargo list.
Definition: aliencargo.cpp:150
base_t * B_GetCurrentSelectedBase(void)
returns the currently selected base
Definition: cp_base.cpp:1578
int Date_DateToSeconds(const date_t *date)
Convert a date_t date to seconds.
Definition: cp_time.cpp:228
date_t date
Definition: cp_campaign.h:245
character_t chr
Definition: cp_employee.h:119
const objDef_t * def(void) const
Definition: inv_shared.h:469
aircraft_t * AIR_AircraftGetFromIDX(int aircraftIdx)
Returns aircraft for a given global index.
class AlienContainment * alienContainment
Definition: cp_base.h:108
const char * shortname
Definition: cp_rank.h:32
static bool TR_AircraftListSelect(const aircraft_t *aircraft)
Check if an aircraft should be displayed for transfer.
Header file for Transfer stuff.
static const cmdList_t transferCallbacks[]
employeeType_t getType() const
Definition: cp_employee.h:99
int numODs
Definition: q_shared.h:518
bool isReloadable() const
Definition: inv_shared.h:352
rank_t * CL_GetRankByIdx(const int index)
Returns a rank at an index.
Definition: cp_rank.cpp:50
Item cargo class header.
Item * getNext() const
Definition: inv_shared.h:451
linkedList_t * acTeam
Definition: cp_aircraft.h:139
static transferType_t TR_GetTransferType(const char *id)
Returns the transfer type.
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
baseCapacities_t AIR_GetHangarCapacityType(const aircraft_t *aircraft)
Returns capacity type needed for an aircraft.
int E_CountHired(const base_t *const base, employeeType_t type)
Counts hired employees of a given type in a given base.
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.
A base with all it's data.
Definition: cp_base.h:84
base_t * B_GetFoundedBaseByIDX(int baseIdx)
Array bound check for the base index.
Definition: cp_base.cpp:325
linkedList_t * cargo
Definition: aliencargo.h:43
static void TR_InitBaseList(void)
Fills the optionlist with available bases to transfer to.
item instance data, with linked list capability
Definition: inv_shared.h:402
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
static void TR_FillAliens(const base_t *srcBase, const base_t *destBase)
Add aliens to the transfer storages list.
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
#define ERR_DROP
Definition: common.h:211
alien cargo entry
Definition: aliencargo.h:32
int size(void) const
Calculate size of all items in the cargo.
Definition: itemcargo.cpp:184
#define TR_Foreach(var)
Definition: cp_transfer.h:46
#define OBJZERO(obj)
Definition: shared.h:178
#define MAX_VAR
Definition: shared.h:36
transferType_t
transfer types
Item cargo class.
Definition: itemcargo.h:41
static void TR_CountAircraftInList(linkedList_t *aircraftList, int capacity[])
Count capacity need of aircraft in lists.
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition: cp_base.cpp:285
const cgame_import_t * cgi
static void TR_CountEmployeeInListArray(linkedList_t *employeeListArray[], int capacity[])
Count capacity need of employee in array of lists.
int idx
Definition: cp_base.h:85
class ItemCargo * itemCargo
Definition: cp_transfer.h:37
employeeType_t
The types of employees.
Definition: cp_employee.h:30
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
static void TR_Fill_f(void)
Callback for filling list with stuff available for transfer.
ccs_t ccs
Definition: cp_campaign.cpp:62
Definition: cmd.h:86
Engine-side time information in the game.
Definition: common.h:290
static transfer_t tr
date_t Date_Substract(date_t a, const date_t &b)
Substract the second date from the first and return the result.
Definition: cp_time.cpp:285
Campaign geoscape time header.
static void TR_FillEmployees(const base_t *srcBase, const base_t *destBase)
Add employees to the transfer storages list.
Item * getNextItem(const Item *prev) const
Definition: inv_shared.cpp:671
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
char * name
Definition: cp_building.h:79
const char * name
Definition: inv_shared.h:267
Alien containment class header.
static void TR_TransferStart_f(void)
Starts the transfer.
static transferType_t currentTransferType
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
Definition: cp_aircraft.h:201
int getDead(const teamDef_t *team) const
Return number of dead alien bodies of a type in the cargo.
Definition: aliencargo.cpp:117
baseCapacities_t
All possible capacities in base.
Definition: cp_capacity.h:27
AlienCargo(void)
Creates and initializes AlienCargo object.
Definition: aliencargo.cpp:206
linkedList_t * employees[MAX_EMPL]
Definition: cp_transfer.h:39
transfer_t * TR_TransferStart(base_t *srcBase, transfer_t &transData)
Starts a transfer.
int B_AntimatterInBase(const base_t *base)
returns the amount of antimatter stored in a base
Definition: cp_base.cpp:2611
#define TR_ForeachEmployee(var, transfer, employeeType)
Definition: cp_transfer.h:47
QGL_EXTERN GLint i
Definition: r_gl.h:113
const Container * getNextCont(const Container *prev, bool inclTemp=false) const
Definition: inv_shared.cpp:722
void TR_InitCallbacks(void)
CASSERT(lengthof(transferTypeIDs)==TRANS_TYPE_MAX)
Employee * E_GetEmployeeFromChrUCN(int uniqueCharacterNumber)
Searches all employee for the ucn (character id)
base_t * destBase
Definition: cp_transfer.h:32
const char * E_GetEmployeeString(employeeType_t type, int n)
Convert employeeType_t to translated string.
static void TR_TransferListClear_f(void)
Unload everything from transfer cargo back to base.
static char const *const transferTypeIDs[]
transfer typeID strings
Alien cargo class header.
Transfer information (they are being stored in ccs.transfers).
Definition: cp_transfer.h:31
const objDef_t * ammoDef(void) const
Definition: inv_shared.h:460
#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
building_t buildingTemplates[MAX_BUILDINGS]
Definition: cp_campaign.h:338
Header file for single player campaign control.
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
Inventory inv
Definition: chr_shared.h:392
const teamDef_t *IMPORT * Com_GetTeamDefinitionByID(const char *team)
int getAlive(const teamDef_t *team) const
Return number of alive aliens of a type in the cargo.
Definition: aliencargo.cpp:100
static void TR_DestinationCapacityList_f(void)
Callback for assemble destination base capacity list.
#define lengthof(x)
Definition: shared.h:105
static void TR_ClearTempCargo(void)
Clear temporary cargo arrays.
#define Q_streq(a, b)
Definition: shared.h:136
static void TR_TransferClose_f(void)
Closes Transfer Menu and resets temp arrays.
Store capacities in base.
Definition: cp_capacity.h:41
buildingType_t buildingType
Definition: cp_building.h:110
An aircraft with all it's data.
Definition: cp_aircraft.h:114
#define TR_ForeachAircraft(var, transfer)
Definition: cp_transfer.h:48
const char uiNode_t *IMPORT * UI_AddOption(uiNode_t **tree, const char *name, const char *label, const char *value)
linkedList_t *IMPORT * LIST_GetPointer(linkedList_t *list, const void *data)
linkedList_t * list(void) const
Returns a copy of the cargo list.
Definition: itemcargo.cpp:156
static void TR_SelectBase_f(void)
Callback to select destination base.
#define ANTIMATTER_ITEM_ID
Definition: cp_research.h:35
class AlienCargo * alienCargo
Definition: cp_transfer.h:38
linkedList_t * aircraft
Definition: cp_transfer.h:40
baseCapacities_t B_GetCapacityFromBuildingType(buildingType_t type)
Get the capacity associated to a building type.
Definition: cp_base.cpp:415
class Employee * pilot
Definition: cp_aircraft.h:141
const char *IMPORT * Cmd_Argv(int n)
const char * CP_SecondConvert(int second)
Converts a number of second into a char to display.
Definition: cp_time.cpp:56
item cargo entry
Definition: itemcargo.h:32
void TR_ShutdownCallbacks(void)
const char * id
Definition: inv_shared.h:268
static void TR_TransferBaseSelect(base_t *srcbase, base_t *destbase)
Callback for base list click.
static void TR_FillAircraft(const base_t *srcBase, const base_t *destBase)
Add aircraft to the transfer storages list.
bool isHiredInBase(const base_t *const base) const
Checks whether the given employee is in the given base.
Definition: cp_employee.h:94
int getAmount(const objDef_t *od) const
Returns amount of an item in the cargo.
Definition: itemcargo.cpp:131
bool B_ItemIsStoredInBaseStorage(const objDef_t *obj)
Check if an item is stored in storage.
Definition: cp_base.cpp:2558