UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cp_base_callbacks.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24 
25 #include "../../cl_shared.h"
26 #include "cp_campaign.h"
27 #include "cp_base_callbacks.h"
28 #include "cp_base.h"
29 #include "cp_capacity.h"
30 #include "cp_geoscape.h"
31 #include "cp_popup.h"
32 #include "cp_time.h"
33 #include "cp_ufo.h"
34 #include "../../ui/ui_dataids.h"
35 #include "aliencontainment.h"
36 
38 #define CREATE_NEW_BASE_ID -1
39 
41 
45 static void B_Destroy_AntimaterStorage_f (void)
46 {
47  base_t* base;
48  const float prob = frand();
49 
50  if (cgi->Cmd_Argc() < 4) {
51  cgi->Com_Printf("Usage: %s <probability> <baseID> <buildingType>\n", cgi->Cmd_Argv(0));
52  return;
53  }
54 
55  base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(2)));
56  if (!base)
57  return;
58  if (CAP_GetCurrent(base, CAP_ANTIMATTER) <= 0)
59  return;
60 
62 
63  if (base->baseStatus != BASE_WORKING)
64  return;
65 
66  if (prob < atof(cgi->Cmd_Argv(1))) {
67  MS_AddNewMessage(_("Notice"), va(_("%s has been destroyed by an antimatter storage breach."), base->name));
68  cgi->UI_PopWindow(false);
69  B_Destroy(base);
70  }
71 }
72 
77 static void B_SelectBase_f (void)
78 {
79  int baseID;
80 
81  if (cgi->Cmd_Argc() < 2) {
82  cgi->Com_Printf("Usage: %s <baseID>\n", cgi->Cmd_Argv(0));
83  return;
84  }
85  baseID = atoi(cgi->Cmd_Argv(1));
86  /* check against MAX_BASES here! - only -1 will create a new base
87  * if we would check against ccs.numBases here, a click on the base selector
88  * base nodes would try to select unfounded bases */
89  if (baseID >= 0 && baseID < MAX_BASES) {
90  const base_t* base = B_GetFoundedBaseByIDX(baseID);
91  /* don't create a new base if the index was valid */
92  if (base)
93  B_SelectBase(base);
94  } else if (baseID == CREATE_NEW_BASE_ID) {
95  /* create a new base */
96  B_SelectBase(nullptr);
97  }
98 }
99 
103 static void B_SetBaseTitle_f (void)
104 {
105  int baseCount = B_GetCount();
106 
107  if (baseCount < MAX_BASES) {
108  char baseName[MAX_VAR];
109 
110  if (baseCount > 0) {
111  int j;
112  int i = 2;
113  do {
114  j = 0;
115  Com_sprintf(baseName, lengthof(baseName), _("Base #%i"), i);
116  while (j <= baseCount && !Q_streq(baseName, ccs.bases[j].name)) {
117  j++;
118  }
119  } while (i++ <= baseCount && j <= baseCount);
120  } else {
121  Q_strncpyz(baseName, _("Home"), lengthof(baseName));
122  }
123 
124  cgi->Cvar_Set("mn_base_title", "%s", baseName);
125  } else {
126  MS_AddNewMessage(_("Notice"), _("You've reached the base limit."));
127  cgi->UI_PopWindow(false); /* remove the new base popup */
128  }
129 }
130 
135 static void B_BuildBase_f (void)
136 {
137  const campaign_t* campaign = ccs.curCampaign;
138 
139  if (ccs.mapAction == MA_NEWBASE)
141 
142  if (ccs.credits - campaign->basecost > 0) {
143  const nation_t* nation;
144  const char* baseName = mn_base_title->string;
145  base_t* base;
146  /* there may be no " in the base name */
147  if (!Com_IsValidName(baseName))
148  baseName = _("Base");
149 
150  base = B_Build(campaign, ccs.newBasePos, baseName);
151  if (!base)
152  cgi->Com_Error(ERR_DROP, "Cannot build base");
153 
154  CP_UpdateCredits(ccs.credits - campaign->basecost);
155  nation = GEO_GetNation(base->pos);
156  if (nation)
157  Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new base has been built: %s (nation: %s)"), mn_base_title->string, _(nation->name));
158  else
159  Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new base has been built: %s"), mn_base_title->string);
161 
162  /* First base */
163  if (ccs.campaignStats.basesBuilt == 1)
164  B_SetUpFirstBase(campaign, base);
165 
166  cgi->Cvar_SetValue("mn_base_count", B_GetCount());
167  B_SelectBase(base);
168  } else {
171  GEO_SetOverlay("radar", 0);
172 
173  CP_GameTimeStop();
174  CP_Popup(_("Notice"), "%s", _("Not enough credits to set up a new base."));
175  }
176 }
177 
181 static void B_ChangeBaseName_f (void)
182 {
183  if (cgi->Cmd_Argc() < 3) {
184  cgi->Com_Printf("Usage: %s <baseIDX> \"<new base name>\"\n", cgi->Cmd_Argv(0));
185  return;
186  }
187  base_t* base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
188  if (!base) {
189  cgi->Com_Printf("Invalid base idx: %s\n", cgi->Cmd_Argv(1));
190  return;
191  }
192 
193  /* basename should not contain double-quote character */
194  if (!Com_IsValidName(cgi->Cmd_Argv(2))) {
195  /* Cancel update, set the cvar to the original name */
196  cgi->Cvar_Set("mn_base_title", "%s", base->name);
197  return;
198  }
199 
200  B_SetName(base, cgi->Cmd_Argv(2));
201 }
202 
209 static void B_BaseInit_f (void)
210 {
211  if (cgi->Cmd_Argc() < 2) {
212 #if 0
213  cgi->Com_Printf("Usage: %s <baseIDX>\n", cgi->Cmd_Argv(0));
214  return;
215 #endif
216  }
217  base_t* base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
218  if (!base)
219  base = B_GetCurrentSelectedBase();
220  if (!base) {
221  cgi->Com_Printf("Invalid base idx: %s\n", cgi->Cmd_Argv(1));
222  return;
223  }
224 
225  /* make sure the credits cvar is up-to-date */
227 
228  /* activate or deactivate the aircraft button */
229  if (AIR_AircraftAllowed(base)) {
230  if (AIR_BaseHasAircraft(base))
231  cgi->UI_ExecuteConfunc("update_basebutton aircraft false \"%s\"", _("Aircraft management and crew equipment"));
232  else
233  cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("Buy or produce at least one aircraft first."));
234  } else {
235  cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("No Hangar operating at this base."));
236  }
237 
238  if (BS_BuySellAllowed(base))
239  cgi->UI_ExecuteConfunc("update_basebutton buysell false \"%s\"", _("Buy/Sell equipment, aircraft and UGV"));
240  else
241  cgi->UI_ExecuteConfunc("update_basebutton buysell true \"%s\"", _("No Storage operating at this base."));
242 
243  if (B_GetCount() > 1)
244  cgi->UI_ExecuteConfunc("update_basebutton transfer false \"%s\"", _("Transfer equipment, vehicles, aliens and employees to other bases"));
245  else
246  cgi->UI_ExecuteConfunc("update_basebutton transfer true \"%s\"", _("Build at least a second base to transfer equipment or personnel"));
247 
248  if (RS_ResearchAllowed(base))
249  cgi->UI_ExecuteConfunc("update_basebutton research false \"%s\"", _("Research new technology"));
250  else
251  cgi->UI_ExecuteConfunc("update_basebutton research true \"%s\"", _("No Laboratory operating at this base."));
252 
253  if (PR_ProductionAllowed(base))
254  cgi->UI_ExecuteConfunc("update_basebutton production false \"%s\"", _("Produce equipment, aircraft and UGV"));
255  else
256  cgi->UI_ExecuteConfunc("update_basebutton production true \"%s\"", _("No Workshop operating at this base."));
257 
258  if (E_HireAllowed(base))
259  cgi->UI_ExecuteConfunc("update_basebutton hire false \"%s\"", _("Hire or dismiss employees"));
260  else
261  cgi->UI_ExecuteConfunc("update_basebutton hire true \"%s\"", _("No Living Quarters operating at this base."));
262 
263  if (AC_ContainmentAllowed(base))
264  cgi->UI_ExecuteConfunc("update_basebutton containment false \"%s\"", _("Manage captured aliens"));
265  else
266  cgi->UI_ExecuteConfunc("update_basebutton containment true \"%s\"", _("No Containment operating at this base."));
267 
268  if (HOS_HospitalAllowed(base))
269  cgi->UI_ExecuteConfunc("update_basebutton hospital false \"%s\"", _("Treat wounded soldiers and perform implant surgery"));
270  else
271  cgi->UI_ExecuteConfunc("update_basebutton hospital true \"%s\"", _("No Hospital operating at this in base."));
272 }
273 
278 static void B_BuildingDestroy_f (void)
279 {
280  if (cgi->Cmd_Argc() < 4) {
281  cgi->Com_Printf("Usage: %s <baseIDX> <column> <row> [confirmed]\n", cgi->Cmd_Argv(0));
282  return;
283  }
284 
285  base_t* base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
286  if (base == nullptr) {
287  cgi->Com_Printf("B_BuildingDestroy_f: Invalid base IDX: %s\n", cgi->Cmd_Argv(1));
288  return;
289  }
290 
291  building_t* building = B_GetBuildingAt(base, atoi(cgi->Cmd_Argv(2)), atoi(cgi->Cmd_Argv(3)));
292  if (building == nullptr) {
293  cgi->Com_Printf("B_BuildingDestroy_f: No valid building at base %i, position (%s, %s)\n",
294  base->idx, cgi->Cmd_Argv(2), cgi->Cmd_Argv(3));
295  return;
296  }
297 
298  if (cgi->Cmd_Argc() == 5 && Q_streq(cgi->Cmd_Argv(4), "confirmed")) {
299  B_BuildingDestroy(building);
300  return;
301  }
302 
303  /* you can't destroy buildings if base is under attack */
304  if (B_IsUnderAttack(base)) {
305  CP_Popup(_("Notice"), _("Base is under attack, you can't destroy buildings!"));
306  return;
307  }
308 
311  if (building->buildingType == B_ENTRANCE) {
312  CP_Popup(_("Destroy Entrance"), _("You can't destroy the entrance of the base!"));
313  return;
314  }
315 
316  if (!B_IsBuildingDestroyable(building)) {
317  CP_Popup(_("Notice"), _("You can't destroy this building! It is the only connection to other buildings!"));
318  return;
319  }
320 
321  if (building->buildingStatus == B_STATUS_WORKING) {
322  const bool hasMoreBases = B_GetCount() > 1;
323  switch (building->buildingType) {
324  case B_ALIEN_CONTAINMENT:
325  if (CAP_GetFreeCapacity(base, cap) < building->capacity) {
326  cgi->UI_PopupButton(_("Destroy Alien Containment"), _("If you destroy this building, you will also kill the aliens inside.\nAre you sure you want to destroy this building?"),
327  "ui_pop;ui_push aliencont;", _("Containment"), _("Go to the Alien Containment without destroying building"),
328  va("ui_pop;building_destroy %i %i %i confirmed;", base->idx, int(building->pos[0]), int(building->pos[1])), _("Destroy"), _("Destroy the building"),
329  hasMoreBases ? "ui_pop;ui_push transfer;" : nullptr, hasMoreBases ? _("Transfer") : nullptr,
330  _("Go to transfer menu without destroying the building"));
331  return;
332  }
333  break;
334  case B_HANGAR:
335  case B_SMALL_HANGAR:
336  if (CAP_GetFreeCapacity(base, cap) <= 0) {
337  cgi->UI_PopupButton(_("Destroy Hangar"), _("If you destroy this hangar, you will also destroy the aircraft inside.\nAre you sure you want to destroy this building?"),
338  "ui_pop;ui_push aircraft_equip;aircraft_select;", _("Go to hangar"), _("Go to hangar without destroying building"),
339  va("ui_pop;building_destroy %i %i %i confirmed;", base->idx, int(building->pos[0]), int(building->pos[1])), _("Destroy"), _("Destroy the building"),
340  hasMoreBases ? "ui_pop;ui_push transfer;" : nullptr, hasMoreBases ? _("Transfer") : nullptr,
341  _("Go to transfer menu without destroying the building"));
342  return;
343  }
344  break;
345  case B_QUARTERS:
346  if (CAP_GetFreeCapacity(base, cap) < building->capacity) {
347  cgi->UI_PopupButton(_("Destroy Quarter"), _("If you destroy this Quarters, every employee inside will be killed.\nAre you sure you want to destroy this building?"),
348  "ui_pop;ui_push employees;employee_list 0;", _("Dismiss"), _("Go to hiring menu without destroying building"),
349  va("ui_pop;building_destroy %i %i %i confirmed;", base->idx, int(building->pos[0]), int(building->pos[1])), _("Destroy"), _("Destroy the building"),
350  hasMoreBases ? "ui_pop;ui_push transfer;" : nullptr, hasMoreBases ? _("Transfer") : nullptr,
351  _("Go to transfer menu without destroying the building"));
352  return;
353  }
354  break;
355  case B_STORAGE:
356  if (CAP_GetFreeCapacity(base, cap) < building->capacity) {
357  cgi->UI_PopupButton(_("Destroy Storage"), _("If you destroy this Storage, every items inside will be destroyed.\nAre you sure you want to destroy this building?"),
358  "ui_pop;ui_push market;buy_type *mn_itemtype", _("Go to storage"), _("Go to buy/sell menu without destroying building"),
359  va("ui_pop;building_destroy %i %i %i confirmed;", base->idx, int(building->pos[0]), int(building->pos[1])), _("Destroy"), _("Destroy the building"),
360  hasMoreBases ? "ui_pop;ui_push transfer;" : nullptr, hasMoreBases ? _("Transfer") : nullptr,
361  _("Go to transfer menu without destroying the building"));
362  return;
363  }
364  break;
365  default:
366  break;
367  }
368  }
369 
370  cgi->UI_PopupButton(_("Destroy building"), _("Are you sure you want to destroy this building?"),
371  nullptr, nullptr, nullptr,
372  va("ui_pop;building_destroy %i %i %i confirmed;", base->idx, int(building->pos[0]), int(building->pos[1])), _("Destroy"), _("Destroy the building"),
373  nullptr, nullptr, nullptr);
374 }
375 
380 static void B_AssembleMap_f (void)
381 {
382  const base_t* base;
383 
384  if (cgi->Cmd_Argc() < 2) {
385  cgi->Com_Printf("Usage: %s <baseIDX>\n", cgi->Cmd_Argv(0));
386  return;
387  }
388  base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
389  if (base == nullptr) {
390  cgi->Com_Printf("B_AssembleMap_f: Invalid base IDX: %s\n", cgi->Cmd_Argv(1));
391  return;
392  }
393 
394  char maps[2048];
395  char coords[2048];
396  B_AssembleMap(maps, sizeof(maps), coords, sizeof(coords), base);
397  cgi->Cbuf_AddText("map %s \"%s\" \"%s\"\n", (GEO_IsNight(base->pos) ? "night" : "day"), maps, coords);
398 }
399 
404 static void B_MakeBaseMapShot_f (void)
405 {
406  if (!cgi->Com_ServerState()) {
407  cgi->Com_Printf("Load the base map before you try to use this function\n");
408  return;
409  }
410 
411  cgi->Cmd_ExecuteString("camsetangles %i %i", 60, 90);
412  cgi->Cvar_SetValue("r_isometric", 1);
413  /* we are interested in the second level only */
414  cgi->Cvar_SetValue("cl_worldlevel", 1);
415  cgi->UI_PushWindow("hud_nohud");
416  /* hide any active console */
417  cgi->Cmd_ExecuteString("toggleconsole");
418  cgi->Cmd_ExecuteString("r_screenshot tga");
419 }
420 
424 static void B_FillBuildingInfo_f (void)
425 {
426  if (cgi->Cmd_Argc() < 3) {
427  cgi->Com_Printf("Usage: %s <baseIDX> <buildingID>\n", cgi->Cmd_Argv(0));
428  return;
429  }
430  base_t* base = B_GetBaseByIDX(atoi(cgi->Cmd_Argv(1)));
431  if (!base) {
432  cgi->Com_Printf("Invalid base idx\n");
433  return;
434  }
436  if (!building) {
437  cgi->Com_Printf("Invalid building id\n");
438  return;
439  }
440 
441  cgi->UI_ExecuteConfunc("show_buildinginfo %s \"%s\" \"%s\" %i %i %i \"%s\" \"%s\"",
442  building->id,
443  building->name,
444  building->image,
445  building->fixCosts,
446  building->varCosts,
447  building->buildTime,
448  va(ngettext("%i day", "%i days", building->buildTime), building->buildTime),
449  building->dependsBuilding ? building->dependsBuilding->name : ""
450  );
451 
452  /* Prevent building more if we reached the limit */
453  if (building->maxCount >= 0 && B_GetNumberOfBuildingsInBaseByTemplate(base, building) >= building->maxCount)
454  return;
455 }
456 
460 static void B_ListBuildings_f (void)
461 {
462  if (cgi->Cmd_Argc() < 2) {
463  cgi->Com_Printf("Usage: %s <baseID>\n", cgi->Cmd_Argv(0));
464  return;
465  }
466  const base_t* const base = B_GetBaseByIDX(atoi(cgi->Cmd_Argv(1)));
467  if (!base)
468  return;
469 
470  for (int i = 0; i < ccs.numBuildingTemplates; i++) {
471  const building_t* const building = &ccs.buildingTemplates[i];
472 
473  /* skip mandatory buildings (like Entrance) which are built automatically */
474  if (building->mandatory)
475  continue;
476  /* only show already researched buildings */
477  if (!RS_IsResearched_ptr(building->tech))
478  continue;
479 
481  capacities_t cap;
482  if (capType != MAX_CAP)
483  cap = *CAP_Get(base, capType);
484  else
485  OBJZERO(cap);
486 
487  assert(building->tpl);
488  const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, building->tpl);
489 
490  cgi->UI_ExecuteConfunc("show_building \"%s\" \"%s\" %i %i %i %i %i %i %i", _(building->name),
491  building->id, building->tpl->capacity, cap.cur, cap.max, count,
492  building->tpl->maxCount, int(building->size[0]), int(building->size[1]));
493  }
494 }
495 
499 static void B_FillMap_f (void)
500 {
501  if (cgi->Cmd_Argc() < 2) {
502  return;
503  }
504 
505  const int baseIdx = atoi(cgi->Cmd_Argv(1));
506 
507  const base_t* const base = B_GetFoundedBaseByIDX(baseIdx);
508  if (base == nullptr)
509  return;
510 
511  for (int baseRow = 0; baseRow < BASE_SIZE; baseRow++) {
512  for (int baseCol = 0; baseCol < BASE_SIZE; baseCol++) {
513  const building_t* const building = B_GetBuildingAt(base, baseCol, baseRow);
514  if (B_IsTileBlocked(base, baseCol, baseRow)) {
515  cgi->UI_ExecuteConfunc("base_building_add %d %d %d %d \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
516  baseCol, baseRow, 1, 1, "", "", "base/invalid", _("Blocked tile"), "");
517  continue;
518  }
519  if (building == nullptr) {
520  cgi->UI_ExecuteConfunc("base_building_add %d %d %d %d \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
521  baseCol, baseRow, 1, 1, "", "", "base/grid", _("Free tile"), "");
522  continue;
523  }
524  if (building->pos[0] != baseCol || building->pos[1] != baseRow)
525  continue;
526  cgi->UI_ExecuteConfunc("base_building_add %d %d %d %d \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
527  baseCol, baseRow, int(building->size[0]), int(building->size[1]),
528  building->id, building->name, building->image, "",
529  !B_IsBuildingBuiltUp(building) ? va(ngettext("%d day", "%d days", int(B_GetConstructionTimeRemain(building))),
530  int(B_GetConstructionTimeRemain(building))) : "");
531  }
532  }
533 }
534 
539 static void B_BuildingOpenAfterClick_f (void)
540 {
541  if (cgi->Cmd_Argc() < 4) {
542  cgi->Com_Printf("Usage: %s <baseIDX> <column> <row>\n", cgi->Cmd_Argv(0));
543  return;
544  }
545 
546  base_t* base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
547  if (base == nullptr) {
548  cgi->Com_Printf("B_BuildingOpenAfterClick_f: Invalid base IDX: %s\n", cgi->Cmd_Argv(1));
549  return;
550  }
551 
552  building_t* building = B_GetBuildingAt(base, atoi(cgi->Cmd_Argv(2)), atoi(cgi->Cmd_Argv(3)));
553  if (building == nullptr) {
554  cgi->Com_Printf("B_BuildingOpenAfterClick_f: No valid building at base %i, position (%s, %s)\n",
555  base->idx, cgi->Cmd_Argv(2), cgi->Cmd_Argv(3));
556  return;
557  }
558 
559  if (!B_GetBuildingStatus(base, building->buildingType)) {
560  UP_OpenWith(building->pedia);
561  return;
562  }
563 
564  switch (building->buildingType) {
565  case B_LAB:
566  if (RS_ResearchAllowed(base))
567  cgi->UI_PushWindow("research");
568  else
569  UP_OpenWith(building->pedia);
570  break;
571  case B_HOSPITAL:
572  if (HOS_HospitalAllowed(base))
573  cgi->Cmd_ExecuteString("ui_push hospital %d", base->idx);
574  else
575  UP_OpenWith(building->pedia);
576  break;
577  case B_ALIEN_CONTAINMENT:
578  if (AC_ContainmentAllowed(base))
579  cgi->UI_PushWindow("aliencont");
580  else
581  UP_OpenWith(building->pedia);
582  break;
583  case B_QUARTERS:
584  if (E_HireAllowed(base))
585  cgi->UI_PushWindow("employees");
586  else
587  UP_OpenWith(building->pedia);
588  break;
589  case B_WORKSHOP:
590  if (PR_ProductionAllowed(base))
591  cgi->UI_PushWindow("production");
592  else
593  UP_OpenWith(building->pedia);
594  break;
595  case B_DEFENCE_LASER:
596  case B_DEFENCE_MISSILE:
597  cgi->UI_PushWindow("basedefence");
598  break;
599  case B_HANGAR:
600  case B_SMALL_HANGAR:
601  if (!AIR_AircraftAllowed(base)) {
602  UP_OpenWith(building->pedia);
603  } else if (AIR_BaseHasAircraft(base)) {
604  cgi->UI_PushWindow("aircraft_equip");
605  } else {
606  cgi->UI_PushWindow("buyaircraft");
607  /* transfer is only possible when there are at least two bases */
608  if (B_GetCount() > 1)
609  CP_Popup(_("Note"), _("No aircraft in this base - You first have to purchase or transfer an aircraft\n"));
610  else
611  CP_Popup(_("Note"), _("No aircraft in this base - You first have to purchase an aircraft\n"));
612  }
613  break;
614  case B_STORAGE:
615  if (BS_BuySellAllowed(base))
616  cgi->UI_PushWindow("market");
617  else
618  UP_OpenWith(building->pedia);
619  break;
620  case B_ANTIMATTER:
621  CP_Popup(_("Information"), "%s %d/%d", _("Antimatter (current/max):"), CAP_GetCurrent(base, CAP_ANTIMATTER), CAP_GetMax(base, CAP_ANTIMATTER));
622  break;
623  default:
624  UP_OpenWith(building->pedia);
625  break;
626  }
627 }
628 
632 static void B_BuildBuilding_f (void)
633 {
634  if (cgi->Cmd_Argc() < 5) {
635  cgi->Com_Printf("Usage: %s <baseIDX> <buildingID> <column> <row>\n", cgi->Cmd_Argv(0));
636  return;
637  }
638 
639  base_t* base = B_GetBaseByIDX(atoi(cgi->Cmd_Argv(1)));
640  if (!base) {
641  cgi->Com_Printf("Invalid base idx\n");
642  return;
643  }
644 
646  if (!building) {
647  cgi->Com_Printf("Invalid building id\n");
648  return;
649  }
650 
651  const int column = atoi(cgi->Cmd_Argv(3));
652  const int row = atoi(cgi->Cmd_Argv(4));
653  if (column < 0 || row < 0 || column >= BASE_SIZE || row >= BASE_SIZE) {
654  cgi->Com_Printf("Invalid building position (%s, %s)\n", cgi->Cmd_Argv(3), cgi->Cmd_Argv(4));
655  return;
656  }
657 
658  if (column + int(building->size[0]) > BASE_SIZE || row + int(building->size[1]) > BASE_SIZE) {
659  cgi->Com_Printf("Building doesn't fit position (%s, %s), size (%d, %d)\n",
660  cgi->Cmd_Argv(3), cgi->Cmd_Argv(4), int(building->size[0]), int(building->size[1]));
661  return;
662  }
663 
664  if (!CP_CheckCredits(building->fixCosts)) {
665  CP_Popup(_("Notice"), _("Not enough credits to build this\n"));
666  return;
667  }
668 
669  if (B_BuildBuilding(base, building, column, row) != nullptr) {
670  cgi->S_StartLocalSample("geoscape/build-place", 1.0f);
671  cgi->Cmd_ExecuteString("ui_push bases %d", base->idx);
672  }
673 }
674 
676 static const cmdList_t baseCallbacks[] = {
677  {"basemapshot", B_MakeBaseMapShot_f, "Command to make a screenshot for the baseview with the correct angles"},
678  {"mn_base_select", B_SelectBase_f, "Select a founded base by index"},
679  {"mn_base_build", B_BuildBase_f, nullptr},
680  {"mn_set_base_title", B_SetBaseTitle_f, nullptr},
681  {"base_changename", B_ChangeBaseName_f, "Called after editing the cvar base name"},
682  {"base_init", B_BaseInit_f, nullptr},
683  {"base_assemble", B_AssembleMap_f, "Called to assemble the current selected base"},
684  {"building_destroy", B_BuildingDestroy_f, "Function to destroy a building (select via right click in baseview first)"},
685  {"building_amdestroy", B_Destroy_AntimaterStorage_f, "Function called if antimatter storage destroyed"},
686  {"base_selectbuilding", B_BuildingOpenAfterClick_f, nullptr},
687  {"ui_list_buildings", B_ListBuildings_f, "Lists buildings built or can be built on a base and their capacities"},
688  {"ui_show_buildinginfo", B_FillBuildingInfo_f, "Opens the building information window in construction mode"},
689  {"ui_base_fillmap", B_FillMap_f, nullptr},
690  {"ui_build_building", B_BuildBuilding_f, nullptr},
691  {nullptr, nullptr, nullptr}
692 };
693 
695 void B_InitCallbacks (void)
696 {
697  mn_base_title = cgi->Cvar_Get("mn_base_title", "", 0, "The title of the current base");
698  cgi->Cvar_Set("mn_base_cost", _("%i c"), ccs.curCampaign->basecost);
699  cgi->Cvar_SetValue("mn_base_count", B_GetCount());
700  cgi->Cvar_SetValue("mn_base_max", MAX_BASES);
701 
702  cgi->Cmd_TableAddList(baseCallbacks);
703 }
704 
707 {
708  cgi->Cmd_TableRemoveList(baseCallbacks);
709 
710  cgi->Cvar_Delete("mn_base_max");
711  cgi->Cvar_Delete("mn_base_cost");
712  cgi->Cvar_Delete("mn_base_title");
713  cgi->Cvar_Delete("mn_base_count");
714 }
base_t bases[MAX_BASES]
Definition: cp_campaign.h:281
float B_GetConstructionTimeRemain(const building_t *building)
Returns the time remaining time of a building construction.
Definition: cp_building.cpp:51
const char * id
Definition: cp_building.h:78
#define CREATE_NEW_BASE_ID
Used from menu scripts as parameter for mn_base_select.
bool AC_ContainmentAllowed(const base_t *base)
Returns true if the current base is able to handle captured aliens.
void UP_OpenWith(const char *techID)
Opens the UFOpaedia from everywhere with the entry given through name.
A building with all it's data.
Definition: cp_building.h:73
void B_ShutdownCallbacks(void)
void B_InitCallbacks(void)
static void B_AssembleMap_f(void)
Builds a base map for tactical combat.
Nation definition.
Definition: cp_nation.h:44
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
static void B_BaseInit_f(void)
Initialises base.
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition: cp_base.cpp:477
static const cmdList_t baseCallbacks[]
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 B_GetNumberOfBuildingsInBaseByTemplate(const base_t *base, const building_t *tpl)
Counts the number of buildings of a particular type in a base.
Definition: cp_base.cpp:1353
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
#define _(String)
Definition: cl_shared.h:43
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
#define B_IsUnderAttack(base)
Definition: cp_base.h:53
struct technology_s * tech
Definition: cp_building.h:111
char name[MAX_VAR]
Definition: cp_base.h:86
bool B_IsBuildingDestroyable(const building_t *building)
Returns if a base building is destroyable.
Definition: cp_base.cpp:223
int credits
Definition: cp_campaign.h:242
#define CAP_Get(base, capacity)
Capacity macros.
Definition: cp_capacity.h:50
baseStatus_t baseStatus
Definition: cp_base.h:102
base_t * B_GetCurrentSelectedBase(void)
returns the currently selected base
Definition: cp_base.cpp:1578
static void B_Destroy_AntimaterStorage_f(void)
onDestroy Callback for Antimatter Storage
#define BASE_SIZE
Definition: cp_base.h:38
static void B_BuildBuilding_f(void)
Build a base building.
static void B_ListBuildings_f(void)
Update the facilities list.
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
bool GEO_IsRadarOverlayActivated(void)
Definition: cp_geoscape.cpp:84
const char * name
Definition: cp_nation.h:46
int basesBuilt
Definition: cp_statistics.h:32
uiMessageListNodeMessage_t * MS_AddNewMessage(const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup, bool playSound)
Adds a new message to message stack.
Definition: cp_messages.cpp:61
static cvar_t * mn_base_title
int buildTime
Definition: cp_building.h:92
void CP_GameTimeStop(void)
Stop game time speed.
Definition: cp_time.cpp:126
#define CAP_GetCurrent(base, capacity)
Definition: cp_capacity.h:52
bool HOS_HospitalAllowed(const base_t *base)
Returns true if you can enter in the hospital.
building_t * B_BuildBuilding(base_t *base, const building_t *buildingTemplate, int col, int row)
Build a new building to the base.
Definition: cp_base.cpp:1279
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
Header file for menu related console command callbacks.
int CAP_GetFreeCapacity(const base_t *base, baseCapacities_t capacityType)
Returns the free capacity of a type.
int B_GetCount(void)
Returns the count of founded bases.
Definition: cp_base.cpp:276
static void B_BuildingOpenAfterClick_f(void)
Opens menu on clicking a building in Baseview.
const struct building_s * dependsBuilding
Definition: cp_building.h:112
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
vec2_t pos
Definition: cp_building.h:104
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
#define ngettext(x, y, cnt)
Definition: g_local.h:40
#define ERR_DROP
Definition: common.h:211
bool mandatory
Definition: cp_building.h:105
#define OBJZERO(obj)
Definition: shared.h:178
bool AIR_BaseHasAircraft(const base_t *base)
Checks whether there is any aircraft assigned to the given base.
Definition: cp_aircraft.cpp:65
#define MAX_VAR
Definition: shared.h:36
void CAP_RemoveAntimatterExceedingCapacity(base_t *base)
Remove exceeding antimatter if an antimatter tank has been destroyed.
Definition: cp_capacity.cpp:38
void CP_Popup(const char *title, const char *text,...)
Wrapper around UI_Popup.
Definition: cp_popup.cpp:473
const cgame_import_t * cgi
static void B_BuildBase_f(void)
Constructs a new base.
int idx
Definition: cp_base.h:85
static void B_BuildingDestroy_f(void)
Destroy a base building.
void B_SetUpFirstBase(const campaign_t *campaign, base_t *base)
Setup aircraft and equipment for first base. Uses the campaign scriptable equipmentlist.
Definition: cp_base.cpp:1107
void CP_UpdateCredits(int credits)
Sets credits and update mn_credits cvar.
static void B_MakeBaseMapShot_f(void)
Makes a mapshot - called by basemapshot script command.
mapAction_t mapAction
Definition: cp_campaign.h:260
ccs_t ccs
Definition: cp_campaign.cpp:62
stats_t campaignStats
Definition: cp_campaign.h:378
Definition: cmd.h:86
int fixCosts
Definition: cp_building.h:83
base_t * B_GetBaseByIDX(int baseIdx)
Array bound check for the base index. Will also return unfounded bases as long as the index is in the...
Definition: cp_base.cpp:312
Campaign geoscape time header.
static void B_FillBuildingInfo_f(void)
Script function for clicking the building list text field.
Header for Geoscape management.
cvar_t *IMPORT * Cvar_Get(const char *varName, const char *value, int flags, const char *desc)
bool RS_ResearchAllowed(const base_t *base)
Returns true if the current base is able to handle research.
building_t * B_GetBuildingTemplateSilent(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
void B_Destroy(base_t *base)
Destroy a base.
Definition: cp_base.cpp:913
char * name
Definition: cp_building.h:79
char cp_messageBuffer[MAX_MESSAGE_TEXT]
Definition: cp_messages.cpp:31
Alien containment class header.
bool AIR_AircraftAllowed(const base_t *base)
Returns true if the current base is able to handle aircraft.
bool GEO_IsNight(const vec2_t pos)
Check whether given position is Day or Night.
QGL_EXTERN GLuint count
Definition: r_gl.h:99
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define CAP_GetMax(base, capacity)
Definition: cp_capacity.h:51
bool PR_ProductionAllowed(const base_t *base)
Returns true if the current base is able to produce items.
Definition: cp_produce.cpp:595
baseCapacities_t
All possible capacities in base.
Definition: cp_capacity.h:27
bool B_IsBuildingBuiltUp(const building_t *building)
Returns if a building is fully buildt up.
Definition: cp_building.cpp:36
int varCosts
Definition: cp_building.h:83
vec2_t size
Definition: cp_building.h:82
bool BS_BuySellAllowed(const base_t *base)
Returns true if you can buy or sell equipment.
Definition: cp_market.cpp:655
struct building_s * tpl
Definition: cp_building.h:75
#define B_GetBuildingAt(base, x, y)
Definition: cp_base.h:165
float frand(void)
Return random values between 0 and 1.
Definition: mathlib.cpp:506
QGL_EXTERN GLint i
Definition: r_gl.h:113
char * string
Definition: cvar.h:73
static void B_SelectBase_f(void)
Called when a base is opened or a new base is created on geoscape. For a new base the baseID is -1...
bool Com_IsValidName(const char *input)
Checks whether the given input string is allowed to be used as a user-given name string for aircraft...
Definition: shared.cpp:612
const char * pedia
Definition: cp_building.h:80
building_t buildingTemplates[MAX_BUILDINGS]
Definition: cp_campaign.h:338
Header file for single player campaign control.
bool B_AssembleMap(char *maps, size_t mapsLength, char *coords, size_t coordsLength, const base_t *base)
Perform the base assembling in case of an alien attack.
Definition: cp_base.cpp:562
#define lengthof(x)
Definition: shared.h:105
bool E_HireAllowed(const base_t *base)
Returns true if the current base is able to handle employees.
#define Q_streq(a, b)
Definition: shared.h:136
vec3_t pos
Definition: cp_base.h:91
bool CP_CheckCredits(int costs)
Checks whether you have enough credits for something.
static void B_SetBaseTitle_f(void)
Sets the title of the base to a cvar to prepare the rename menu.
Store capacities in base.
Definition: cp_capacity.h:41
buildingType_t buildingType
Definition: cp_building.h:110
bool B_BuildingDestroy(building_t *building)
Removes a building from the given base.
Definition: cp_base.cpp:770
#define MAX_BASES
Definition: cp_base.h:32
campaign_t * curCampaign
Definition: cp_campaign.h:377
void GEO_SetOverlay(const char *overlayID, int status)
Turn overlay on/off.
buildingStatus_t buildingStatus
Definition: cp_building.h:94
Header for base management related stuff.
baseCapacities_t B_GetCapacityFromBuildingType(buildingType_t type)
Get the capacity associated to a building type.
Definition: cp_base.cpp:415
#define B_IsTileBlocked(base, x, y)
Definition: cp_base.h:164
void B_SelectBase(const base_t *base)
Select and opens a base.
Definition: cp_base.cpp:1592
static void B_ChangeBaseName_f(void)
Creates console command to change the name of a base.
base_t * B_Build(const campaign_t *campaign, const vec2_t pos, const char *name, bool fillBase)
Build new base, uses template for the first base.
Definition: cp_base.cpp:1185
nation_t * GEO_GetNation(const vec2_t pos)
Translate nation map color to nation.
const char *IMPORT * Cmd_Argv(int n)
static void B_FillMap_f(void)
Lists building tiles for the Basescape UI.
const char * image
Definition: cp_building.h:80
void B_SetName(base_t *base, const char *name)
Set the base name.
Definition: cp_base.cpp:1173
vec2_t newBasePos
Definition: cp_campaign.h:261