UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_base_callbacks.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, 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
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
77static 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
103static 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
135static void B_BuildBase_f (void)
136{
137 const campaign_t* campaign = ccs.curCampaign;
138
139 if (ccs.mapAction == MA_NEWBASE)
140 ccs.mapAction = MA_NONE;
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
174 CP_Popup(_("Notice"), "%s", _("Not enough credits to set up a new base."));
175 }
176}
177
181static 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
209static 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)
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 */
226 CP_UpdateCredits(ccs.credits);
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
278static 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) {
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
380static 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
404static 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
424static 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 }
435 building_t* building = B_GetBuildingTemplateSilent(cgi->Cmd_Argv(2));
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
460static 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
499static 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
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;
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:
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
632static 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
645 building_t* building = B_GetBuildingTemplateSilent(cgi->Cmd_Argv(2));
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
676static 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
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}
Alien containment class header.
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
#define ERR_DROP
Definition common.h:211
bool AIR_AircraftAllowed(const base_t *base)
Returns true if the current base is able to handle aircraft.
bool AIR_BaseHasAircraft(const base_t *base)
Checks whether there is any aircraft assigned to the given base.
bool AC_ContainmentAllowed(const base_t *base)
Returns true if the current base is able to handle captured aliens.
bool B_BuildingDestroy(building_t *building)
Removes a building from the given base.
Definition cp_base.cpp:771
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
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
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:563
void B_SelectBase(const base_t *base)
Select and opens a base.
Definition cp_base.cpp:1592
int B_GetCount(void)
Returns the count of founded bases.
Definition cp_base.cpp:277
base_t * B_GetCurrentSelectedBase(void)
returns the currently selected base
Definition cp_base.cpp:1578
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:313
bool B_IsBuildingDestroyable(const building_t *building)
Returns if a base building is destroyable.
Definition cp_base.cpp:224
void B_SetName(base_t *base, const char *name)
Set the base name.
Definition cp_base.cpp:1173
void B_Destroy(base_t *base)
Destroy a base.
Definition cp_base.cpp:914
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
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition cp_base.cpp:478
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
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
Header for base management related stuff.
#define B_IsTileBlocked(base, x, y)
Definition cp_base.h:164
bool PR_ProductionAllowed(const base_t *base)
Returns true if the current base is able to produce items.
#define BASE_SIZE
Definition cp_base.h:38
#define B_GetBuildingAt(base, x, y)
Definition cp_base.h:165
@ BASE_WORKING
Definition cp_base.h:64
bool E_HireAllowed(const base_t *base)
Returns true if the current base is able to handle employees.
bool RS_ResearchAllowed(const base_t *base)
Returns true if the current base is able to handle research.
#define B_IsUnderAttack(base)
Definition cp_base.h:53
bool HOS_HospitalAllowed(const base_t *base)
Returns true if you can enter in the hospital.
#define MAX_BASES
Definition cp_base.h:32
bool BS_BuySellAllowed(const base_t *base)
Returns true if you can buy or sell equipment.
static void B_BuildingOpenAfterClick_f(void)
Opens menu on clicking a building in Baseview.
void B_InitCallbacks(void)
static void B_BuildingDestroy_f(void)
Destroy a base building.
static void B_ListBuildings_f(void)
Update the facilities list.
void B_ShutdownCallbacks(void)
static void B_BaseInit_f(void)
Initialises base.
static cvar_t * mn_base_title
static void B_BuildBase_f(void)
Constructs a new base.
static void B_ChangeBaseName_f(void)
Creates console command to change the name of a base.
#define CREATE_NEW_BASE_ID
Used from menu scripts as parameter for mn_base_select.
static void B_SetBaseTitle_f(void)
Sets the title of the base to a cvar to prepare the rename menu.
static void B_MakeBaseMapShot_f(void)
Makes a mapshot - called by basemapshot script command.
static void B_Destroy_AntimaterStorage_f(void)
onDestroy Callback for Antimatter Storage
static void B_AssembleMap_f(void)
Builds a base map for tactical combat.
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.
static void B_FillBuildingInfo_f(void)
Script function for clicking the building list text field.
static void B_FillMap_f(void)
Lists building tiles for the Basescape UI.
static void B_BuildBuilding_f(void)
Build a base building.
static const cmdList_t baseCallbacks[]
Header file for menu related console command callbacks.
building_t * B_GetBuildingTemplateSilent(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
bool B_IsBuildingBuiltUp(const building_t *building)
Returns if a building is fully buildt up.
float B_GetConstructionTimeRemain(const building_t *building)
Returns the time remaining time of a building construction.
@ B_ENTRANCE
Definition cp_building.h:64
@ B_QUARTERS
Definition cp_building.h:54
@ B_DEFENCE_LASER
Definition cp_building.h:66
@ B_HANGAR
Definition cp_building.h:58
@ B_STORAGE
Definition cp_building.h:55
@ B_LAB
Definition cp_building.h:53
@ B_HOSPITAL
Definition cp_building.h:57
@ B_WORKSHOP
Definition cp_building.h:56
@ B_SMALL_HANGAR
Definition cp_building.h:60
@ B_DEFENCE_MISSILE
Definition cp_building.h:65
@ B_ALIEN_CONTAINMENT
Definition cp_building.h:59
@ B_ANTIMATTER
Definition cp_building.h:63
@ B_STATUS_WORKING
Definition cp_building.h:36
bool CP_CheckCredits(int costs)
Checks whether you have enough credits for something.
void CP_UpdateCredits(int credits)
Sets credits and update mn_credits cvar.
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
@ MA_NONE
@ MA_NEWBASE
void CAP_RemoveAntimatterExceedingCapacity(base_t *base)
Remove exceeding antimatter if an antimatter tank has been destroyed.
int CAP_GetFreeCapacity(const base_t *base, baseCapacities_t capacityType)
Returns the free capacity of a type.
#define CAP_GetCurrent(base, capacity)
Definition cp_capacity.h:52
baseCapacities_t
All possible capacities in base.
Definition cp_capacity.h:27
@ CAP_ANTIMATTER
Definition cp_capacity.h:35
@ MAX_CAP
Definition cp_capacity.h:37
#define CAP_GetMax(base, capacity)
Definition cp_capacity.h:51
#define CAP_Get(base, capacity)
Capacity macros.
Definition cp_capacity.h:50
bool GEO_IsNight(const vec2_t pos)
Check whether given position is Day or Night.
nation_t * GEO_GetNation(const vec2_t pos)
Translate nation map color to nation.
void GEO_SetOverlay(const char *overlayID, int status)
Turn overlay on/off.
bool GEO_IsRadarOverlayActivated(void)
Header for Geoscape management.
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.
char cp_messageBuffer[MAX_MESSAGE_TEXT]
@ MSG_CONSTRUCTION
Definition cp_messages.h:39
void CP_Popup(const char *title, const char *text,...)
Wrapper around UI_Popup.
Definition cp_popup.cpp:474
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
void CP_GameTimeStop(void)
Stop game time speed.
Definition cp_time.cpp:126
Campaign geoscape time header.
void UP_OpenWith(const char *techID)
Opens the UFOpaedia from everywhere with the entry given through name.
#define ngettext(x, y, cnt)
Definition g_local.h:40
float frand(void)
Return random values between 0 and 1.
Definition mathlib.cpp:506
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN GLint i
Definition r_gl.h:113
#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
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
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
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
A base with all it's data.
Definition cp_base.h:84
baseStatus_t baseStatus
Definition cp_base.h:102
int idx
Definition cp_base.h:85
char name[MAX_VAR]
Definition cp_base.h:86
vec3_t pos
Definition cp_base.h:91
A building with all it's data.
Definition cp_building.h:73
struct building_s * tpl
Definition cp_building.h:75
vec2_t size
Definition cp_building.h:82
const char * image
Definition cp_building.h:80
char * name
Definition cp_building.h:79
const struct building_s * dependsBuilding
buildingType_t buildingType
buildingStatus_t buildingStatus
Definition cp_building.h:94
const char * pedia
Definition cp_building.h:80
const char * id
Definition cp_building.h:78
struct technology_s * tech
Store capacities in base.
Definition cp_capacity.h:41
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
Nation definition.
Definition cp_nation.h:46
const char * name
Definition cp_nation.h:48