UFO: Alien Invasion
Loading...
Searching...
No Matches
test_campaign.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 "test_shared.h"
26#include "../client/DateTime.h"
27#include "../client/client.h"
28#include "../client/cl_lua.h"
30#include "../client/renderer/r_state.h" /* r_state */
44#include "../shared/parse.h"
45#include "../shared/images.h"
46
47static const int TAG_INVENTORY = 1538;
48
49static void FreeInventory (void* data)
50{
52}
53
54static void* AllocInventoryMemory (size_t size)
55{
57}
58
63
65
66static inline void ResetInventoryList (void)
67{
68 cls.i.destroyInventoryInterface();
69 cls.i.initInventory("testCampaign", &csi, &inventoryImport);
70}
71
72static campaign_t* GetCampaign (void)
73{
74 return CP_GetCampaign("main");
75}
76
77class CampaignTest: public ::testing::Test {
78protected:
79 static void SetUpTestCase()
80 {
81 TEST_Init();
82
83 cl_genericPool = Mem_CreatePool("Client: Generic");
84 cp_campaignPool = Mem_CreatePool("Client: Local (per game)");
85 cp_missiontest = Cvar_Get("cp_missiontest", "0");
86 vid_imagePool = Mem_CreatePool("Vid: Image system");
87
88 r_state.active_texunit = &r_state.texunits[0];
89 R_FontInit();
90 CL_InitLua();
91 UI_Init();
93
94 OBJZERO(cls);
95 Com_ParseScripts(false);
96
97 Cmd_ExecuteString("game_setmode campaign");
98
99 Cmd_AddCommand("msgoptions_set", Cmd_Dummy_f);
100
102 cls.realtime = Sys_Milliseconds();
103 }
104
105 static void TearDownTestCase()
106 {
109 }
110
111 void SetUp()
112 {
113 campaign_t* campaign;
114
117 campaign = GetCampaign();
118 CP_ReadCampaignData(campaign);
119
121
123
124 GEO_Shutdown();
125 GEO_Init(campaign->map);
126
127 ccs.curCampaign = campaign;
128 }
129};
130
131static installation_t* CreateInstallation (const char* name, const vec2_t pos)
132{
134 installation_t* installation = INS_Build(installationTemplate, pos, name);
135
136 /* fake the build time */
137 installation->buildStart = ccs.date.getDateAsDays() - installation->installationTemplate->buildTime;
139
140 return installation;
141}
142
143static base_t* CreateBase (const char* name, const vec2_t pos, bool fillBase = false)
144{
145 const campaign_t* campaign = GetCampaign();
146
147 RS_InitTree(campaign, false);
148 E_InitialEmployees(campaign);
149 base_t* base = B_Build(campaign, pos, name, fillBase);
150
151 /* First base */
152 if (ccs.campaignStats.basesBuilt == 1)
153 B_SetUpFirstBase(campaign, base);
154
155 return base;
156}
157
158TEST_F(CampaignTest, testAircraftHandling)
159{
160 const vec2_t destination = { 10, 10 };
161 base_t* base;
162 aircraft_t* aircraft;
163 aircraft_t* newAircraft;
164 aircraft_t* aircraftTemplate;
165 int firstIdx;
166 int initialCount;
167 int count;
168 int newFound;
169
170 base = CreateBase("unittestaircraft", destination);
171 ASSERT_TRUE(nullptr != base);
172
174 aircraft = AIR_GetFirstFromBase(base);
175 ASSERT_TRUE(nullptr != aircraft);
176
177 /* aircraft should have a template */
178 aircraftTemplate = aircraft->tpl;
179 ASSERT_TRUE(nullptr != aircraftTemplate);
180
181 firstIdx = aircraft->idx;
182 initialCount = AIR_BaseCountAircraft(base);
183
184 /* test deletion (part 1) */
185 AIR_DeleteAircraft(aircraft);
187 ASSERT_EQ(count, initialCount - 1);
188
189 /* test addition (part 1) */
190 newAircraft = AIR_NewAircraft(base, aircraftTemplate);
191 ASSERT_TRUE(nullptr != newAircraft);
193 ASSERT_EQ(count, initialCount);
194
195 /* new aircraft assigned to the right base */
196 ASSERT_EQ(newAircraft->homebase, base);
197
198 newFound = 0;
199 AIR_Foreach(a) {
200 /* test deletion (part 2) */
201 ASSERT_NE(firstIdx, a->idx);
202 /* for test addition (part 2) */
203 if (a->idx == newAircraft->idx)
204 newFound++;
205 }
206 /* test addition (part 2) */
207 ASSERT_EQ(newFound, 1);
208
209 /* check if AIR_Foreach iterates through all aircraft */
210 AIR_Foreach(a) {
212 }
213 aircraft = AIR_GetFirstFromBase(base);
214 ASSERT_TRUE(nullptr == aircraft);
216 ASSERT_EQ(count, 0);
217
218 /* cleanup for the following tests */
219 E_DeleteAllEmployees(nullptr);
220
221 base->founded = false;
222}
223
224TEST_F(CampaignTest, testEmployeeHandling)
225{
226 int i;
227
228 for (i = 0; i < MAX_EMPL; i++) {
230 if (type != EMPL_ROBOT) {
231 int cnt;
232 Employee* e = E_CreateEmployee(type, nullptr, nullptr);
233 ASSERT_TRUE(nullptr != e);
234
235 cnt = E_CountUnhired(type);
236 ASSERT_EQ(cnt, 1);
237
239
240 cnt = E_CountUnhired(type);
241 ASSERT_EQ(cnt, 0);
242 }
243 }
244
245 {
246 const int amount = 3;
247 for (i = 0; i < amount; i++) {
248 Employee* e = E_CreateEmployee(EMPL_SOLDIER, nullptr, nullptr);
249 ASSERT_TRUE(nullptr != e);
250 }
251 {
252 int cnt = 0;
254 (void)e;
255 cnt++;
256 }
257
258 ASSERT_EQ(cnt, amount);
259
261 ASSERT_TRUE(E_DeleteEmployee(e));
262 }
263
265 ASSERT_EQ(cnt, 0);
266 }
267 }
268
269 {
270 const ugv_t* ugvType = Com_GetUGVByID("ugv_ares_w");
271 Employee* e = E_CreateEmployee(EMPL_ROBOT, nullptr, ugvType);
272 ASSERT_TRUE(nullptr != e);
273 ASSERT_TRUE(E_DeleteEmployee(e));
274 }
275
276 {
277 int i, cnt;
278 for (i = 0; i < 512; i++) {
279 Employee* e = E_CreateEmployee(EMPL_SOLDIER, nullptr, nullptr);
280 ASSERT_TRUE(nullptr != e);
281
283 ASSERT_EQ(cnt, i + 1);
284 }
285 E_DeleteAllEmployees(nullptr);
286
288 ASSERT_EQ(cnt, 0);
289 }
290}
291
292TEST_F(CampaignTest, testBaseBuilding)
293{
294 ccs.credits = 10000000;
295
296 vec2_t pos = {0, 0};
297 base_t* base = CreateBase("unittestcreatebase", pos);
298
300
301 B_Destroy(base);
302
303 for (int i = 0; i < MAX_EMPL; i++) {
305 ASSERT_EQ(E_CountHired(base, type), 0);
306 }
307
308 /* cleanup for the following tests */
309 E_DeleteAllEmployees(nullptr);
310
311 base->founded = false;
312}
313
314TEST_F(CampaignTest, testAutoMissions)
315{
316 const vec2_t pos = {-73.2, 18.5};
317 base_t* base;
318 missionResults_t result;
319 battleParam_t battleParameters;
320 aircraft_t* aircraft;
321 mission_t* mission;
322 campaign_t* campaign;
323
324 campaign = GetCampaign();
325 ASSERT_TRUE(campaign != nullptr);
326
327 OBJZERO(result);
328 OBJZERO(battleParameters);
329
330 ccs.overallInterest = 36;
332
333 base = CreateBase("unittestautomission", pos);
334 ASSERT_TRUE(nullptr != base);
335
336 aircraft = nullptr;
337 AIR_ForeachFromBase(a, base) {
338 if (AIR_GetTeamSize(a) > 0) {
339 aircraft = a;
340 break;
341 }
342 }
343 ASSERT_TRUE(nullptr != aircraft);
344 ASSERT_TRUE(AIR_GetTeamSize(aircraft) > 0);
345
347 Vector2Copy(pos, mission->pos);
348 mission->posAssigned = true;
349 mission->mapDef = Com_GetMapDefinitionByID("farm2");
350 ASSERT_TRUE(nullptr != mission);
351
352 CP_CreateBattleParameters(mission, &battleParameters, aircraft);
353 AM_Go(mission, aircraft, campaign, &battleParameters, &result);
354
355 ASSERT_TRUE(result.state == WON);
356}
357
358TEST_F(CampaignTest, testTransferItem)
359{
360 const campaign_t* campaign = GetCampaign();
361 const vec2_t pos = {0, 0};
362 const vec2_t posTarget = {51, 0};
364
365 base_t* base = CreateBase("unittesttransferitem", pos);
366 ASSERT_TRUE(nullptr != base);
367 base_t* targetBase = CreateBase("unittesttransferitemtargetbase", posTarget, true);
368 ASSERT_TRUE(nullptr != targetBase);
369 B_SetUpFirstBase(campaign, targetBase);
370
371 const objDef_t* od = INVSH_GetItemByID("assault");
372 ASSERT_TRUE(nullptr != od);
373
374 OBJZERO(tr);
375 tr.itemCargo = new ItemCargo();
376 tr.itemCargo->add(od, 1, 0);
377 tr.destBase = targetBase;
378 tr.itemCargo->add(od, 1, 0);
379
380 transfer_t* transfer = TR_TransferStart(base, tr);
381 ASSERT_TRUE(nullptr != transfer);
382
383 ASSERT_EQ(LIST_Count(ccs.transfers), 1);
384
385 transfer->event = ccs.date + DateTime(1, 0);
386
387 /* check if it's arrived immediately */
389 ASSERT_FALSE(LIST_IsEmpty(ccs.transfers));
390
391 /* check if it arrives (even a second) before it should */
392 ccs.date += DateTime(1, -1);
394 ASSERT_FALSE(LIST_IsEmpty(ccs.transfers));
395
396 /* check if it arrived right when it should */
397 ccs.date += DateTime(0, 1);
399 ASSERT_TRUE(LIST_IsEmpty(ccs.transfers));
400
401 /* Start another transfer to check higher time lapse */
402 transfer = TR_TransferStart(base, tr);
403 ASSERT_TRUE(nullptr != transfer);
404 ASSERT_EQ(LIST_Count(ccs.transfers), 1);
405
406 transfer->event = ccs.date + DateTime(1, 0);
407
408 /* check if it arrived when time passed the deadline by days already */
409 ccs.date += DateTime(2, 0);
411 ASSERT_TRUE(LIST_IsEmpty(ccs.transfers));
412
413 /* Start another transfer to check higher time lapse */
414 transfer = TR_TransferStart(base, tr);
415 ASSERT_TRUE(nullptr != transfer);
416 ASSERT_EQ(LIST_Count(ccs.transfers), 1);
417
418 transfer->event = ccs.date + DateTime(1, 0);
419
420 /* check if it arrived when time passed the deadline by days already */
421 ccs.date += DateTime(1, 1);
423 ASSERT_TRUE(LIST_IsEmpty(ccs.transfers));
424
425
426 /* cleanup for the following tests */
427 E_DeleteAllEmployees(nullptr);
428 delete tr.itemCargo;
429 tr.itemCargo = nullptr;
430
431 base->founded = false;
432}
433
434TEST_F(CampaignTest, testUFORecovery)
435{
436 const vec2_t pos = {0, 0};
437 const aircraft_t* ufo;
438 storedUFO_t* storedUFO;
439 installation_t* installation;
440 DateTime date(ccs.date);
441
442 ufo = AIR_GetAircraft("craft_ufo_fighter");
443 ASSERT_TRUE(nullptr != ufo);
444
445 CreateBase("unittestproduction", pos);
446
447 installation = CreateInstallation("unittestuforecovery", pos);
448
449 date += DateTime(1, 0);
450 storedUFO = US_StoreUFO(ufo, installation, date, 1.0);
451 ASSERT_TRUE(nullptr != storedUFO);
452 ASSERT_EQ(storedUFO->status, SUFO_RECOVERED);
453
455
456 ASSERT_EQ(storedUFO->status, SUFO_RECOVERED);
457
458 ccs.date += DateTime(1, 0);
459
461
462 ASSERT_EQ(storedUFO->status, SUFO_STORED);
463
464 /* cleanup for the following tests */
465 E_DeleteAllEmployees(nullptr);
466}
467
468TEST_F(CampaignTest, testAlienPSIDevice)
469{
470 RS_MarkResearchable(nullptr, true);
471
472 technology_t* alienPsiDevice = RS_GetTechByID("rs_alien_psi_device");
473 RS_MarkOneResearchable(alienPsiDevice);
474 ASSERT_TRUE(alienPsiDevice->statusResearchable);
475}
476
477TEST_F(CampaignTest, testResearch)
478{
479 RS_MarkResearchable(nullptr, true);
480
481 technology_t* laserTech = RS_GetTechByID("rs_laser");
482 ASSERT_TRUE(nullptr != laserTech);
483 technology_t* otherLaserTech = RS_GetTechByID("rs_baselaser");
484 ASSERT_TRUE(nullptr != otherLaserTech);
485
486 const vec2_t pos = {0, 0};
487 base_t* base = CreateBase("unittestbase", pos);
488
489 ASSERT_TRUE(laserTech->statusResearchable);
490
491 RS_AssignScientist(laserTech, base);
492
493 ASSERT_EQ(laserTech->base, base);
494 ASSERT_EQ(laserTech->scientists, 1);
495 ASSERT_EQ(laserTech->statusResearch, RS_RUNNING);
496
497 ASSERT_FALSE(otherLaserTech->statusResearchable);
498
499 const int n = laserTech->time * (1.0f / ccs.curCampaign->researchRate);
500 for (int i = 0; i < n; i++) {
501 const int finished = RS_ResearchRun();
502 ASSERT_EQ(finished, 0) << "Did not expect to finish a research (#" << finished << ", i:" << i << ")";
503 }
504
505 ASSERT_EQ(laserTech->statusResearch, RS_RUNNING);
506 ASSERT_EQ(RS_ResearchRun(), 1);
507 ASSERT_EQ(laserTech->statusResearch, RS_FINISH);
508
509 ASSERT_TRUE(otherLaserTech->statusResearchable);
510
511 /* cleanup for the following tests */
512 E_DeleteAllEmployees(nullptr);
513
514 base->founded = false;
515}
516
517TEST_F(CampaignTest, testProductionItem)
518{
519 const vec2_t pos = {0, 0};
520 base_t* base;
521 const objDef_t* od;
522 const technology_t* tech;
523 int old;
524 int i, n;
526 production_t* prod;
527
528 base = CreateBase("unittestproduction", pos);
529
530 ASSERT_TRUE(B_AtLeastOneExists());
531 ASSERT_TRUE(B_GetBuildingStatus(base, B_WORKSHOP));
532 ASSERT_TRUE(E_CountHired(base, EMPL_WORKER) > 0);
533 ASSERT_TRUE(PR_ProductionAllowed(base));
534
535 od = INVSH_GetItemByID("assault");
536 ASSERT_TRUE(nullptr != od);
537
539 old = base->storage.numItems[od->idx];
540 prod = PR_QueueNew(base, &data, 1);
541 ASSERT_TRUE(nullptr != prod);
542 tech = RS_GetTechForItem(od);
543 n = PR_GetRemainingMinutes(prod);
544 i = tech->produceTime / PR_WorkersAvailable(base);
545 ASSERT_EQ(i, PR_GetRemainingHours(prod));
546 for (i = 0; i < n; i++) {
548 }
549
550 ASSERT_EQ(old, base->storage.numItems[od->idx]);
552 ASSERT_EQ(old + 1, base->storage.numItems[od->idx]);
553
554 /* cleanup for the following tests */
555 E_DeleteAllEmployees(nullptr);
556
557 base->founded = false;
558}
559
560TEST_F(CampaignTest, testProductionAircraft)
561{
562 const vec2_t pos = {0, 0};
563 base_t* base;
564 const aircraft_t* aircraft;
565 int old;
566 int i, n;
568 production_t* prod;
569
570 base = CreateBase("unittestproduction", pos);
571
572 ASSERT_TRUE(B_AtLeastOneExists());
573 ASSERT_TRUE(B_GetBuildingStatus(base, B_WORKSHOP));
574 ASSERT_TRUE(E_CountHired(base, EMPL_WORKER) > 0);
575 ASSERT_TRUE(PR_ProductionAllowed(base));
576
577 /* Check for production requirements */
578 aircraft = AIR_GetAircraft("craft_inter_stingray");
579 ASSERT_TRUE(nullptr != aircraft);
581 /* no antimatter */
582 ASSERT_TRUE(nullptr == PR_QueueNew(base, &data, 1));
583
585 aircraft = AIR_GetAircraft("craft_inter_stiletto");
586 ASSERT_TRUE(nullptr != aircraft);
588 prod = PR_QueueNew(base, &data, 1);
589 ASSERT_TRUE(nullptr != prod);
590
591 n = PR_GetRemainingMinutes(prod);
592 i = aircraft->tech->produceTime / PR_WorkersAvailable(base);
593 ASSERT_EQ(i, PR_GetRemainingHours(prod));
594 for (i = 0; i < n; i++) {
596 }
597
598 ASSERT_EQ(old, CAP_GetCurrent(base, CAP_AIRCRAFT_SMALL));
600 ASSERT_EQ(old + 1, CAP_GetCurrent(base, CAP_AIRCRAFT_SMALL));
601
602 /* cleanup for the following tests */
603 E_DeleteAllEmployees(nullptr);
604
605 base->founded = false;
606}
607
608TEST_F(CampaignTest, testDisassembly)
609{
610 const vec2_t pos = {0, 0};
611 base_t* base;
612 const aircraft_t* ufo;
613 int old;
614 int i, n;
615 storedUFO_t* storedUFO;
617 installation_t* installation;
618 production_t* prod;
619
620 base = CreateBase("unittestproduction", pos);
621
622 ASSERT_TRUE(B_AtLeastOneExists());
623 ASSERT_TRUE(B_GetBuildingStatus(base, B_WORKSHOP));
624 ASSERT_TRUE(E_CountHired(base, EMPL_WORKER) > 0);
625 ASSERT_TRUE(PR_ProductionAllowed(base));
626
627 ufo = AIR_GetAircraft("craft_ufo_fighter");
628 ASSERT_TRUE(nullptr != ufo);
629
630 installation = CreateInstallation("unittestproduction", pos);
631
632 storedUFO = US_StoreUFO(ufo, installation, ccs.date, 1.0);
633 ASSERT_TRUE(nullptr != storedUFO);
634 ASSERT_EQ(storedUFO->status, SUFO_RECOVERED);
636 prod = PR_QueueNew(base, &data, 1);
637 ASSERT_TRUE(nullptr != prod);
638
639 old = CAP_GetCurrent(base, CAP_ITEMS);
640 n = PR_GetRemainingMinutes(prod);
641 i = storedUFO->comp->time / PR_WorkersAvailable(base);
642 ASSERT_EQ(i, PR_GetRemainingHours(prod));
643 for (i = 0; i < n; i++) {
645 }
646
647 ASSERT_EQ(old, CAP_GetCurrent(base, CAP_ITEMS));
649 ASSERT_NE(old, CAP_GetCurrent(base, CAP_ITEMS));
650
651 /* cleanup for the following tests */
652 E_DeleteAllEmployees(nullptr);
653
654 base->founded = false;
655}
656
658{
659 vec2_t pos;
660 bool coast = false;
661
662 Vector2Set(pos, -51, 0);
663 ASSERT_TRUE(MapIsWater(GEO_GetColor(pos, MAPTYPE_TERRAIN, nullptr)));
664
665 Vector2Set(pos, 51, 0);
666 ASSERT_TRUE(!MapIsWater(GEO_GetColor(pos, MAPTYPE_TERRAIN, nullptr)));
667
668 Vector2Set(pos, 20, 20);
669 ASSERT_TRUE(MapIsWater(GEO_GetColor(pos, MAPTYPE_TERRAIN, nullptr)));
670
671 Vector2Set(pos, -45, 2.5);
672 ASSERT_TRUE(!MapIsWater(GEO_GetColor(pos, MAPTYPE_TERRAIN, &coast)));
673 ASSERT_TRUE(coast);
674}
675
676TEST_F(CampaignTest, testAirFight)
677{
678 const vec2_t destination = { 10, 10 };
679 /* just some random delta time value that is high enough
680 * to ensure that all the weapons are reloaded */
681 const int deltaTime = 1000;
682
683 campaign_t* campaign = GetCampaign();
684
685 base_t* base = CreateBase("unittestairfight", destination);
686 ASSERT_TRUE(nullptr != base);
687
688 int cnt = AIR_BaseCountAircraft(base);
689 int i = 0;
690 AIR_ForeachFromBase(a, base)
691 i++;
692 ASSERT_EQ(i, cnt);
693
694 aircraft_t* aircraft = AIR_GetFirstFromBase(base);
695 ASSERT_TRUE(nullptr != aircraft);
696 aircraft->status = AIR_IDLE;
697 ASSERT_TRUE(AIR_IsAircraftOnGeoscape(aircraft));
698
699 /* ensure that a FIGHTER can spawn */
700 ufoType_t ufoTypes[UFO_MAX];
701 ASSERT_NE(0, UFO_GetAvailableUFOsForMission(INTERESTCATEGORY_INTERCEPT, ufoTypes, false));
702 const aircraft_t* ufoTemplate = UFO_GetByType(ufoTypes[0]); /* the first interceptor will do */
703 ASSERT_TRUE(nullptr != ufoTemplate);
704 ccs.overallInterest = ufoTemplate->ufoInterestOnGeoscape + 1;
705
706 /* prepare the mission */
708 ASSERT_TRUE(nullptr != mission);
709 ASSERT_EQ(mission->stage, STAGE_NOT_ACTIVE);
710 CP_InterceptNextStage(mission);
711 ASSERT_EQ(mission->stage, STAGE_COME_FROM_ORBIT);
712 CP_InterceptNextStage(mission);
713 ASSERT_EQ(mission->stage, STAGE_INTERCEPT);
714 aircraft_t* ufo = mission->ufo;
715 ASSERT_TRUE(nullptr != ufo);
716 ufo->ufotype = ufoTypes[0];
717 /* we have to update the routing data here to be sure that the ufo is
718 * not spawned on the other side of the globe */
719 Vector2Copy(destination, ufo->pos);
720 UFO_SendToDestination(ufo, destination);
721 ASSERT_TRUE(VectorEqual(ufo->pos, base->pos));
722 ASSERT_TRUE(VectorEqual(ufo->pos, aircraft->pos));
723
724 ASSERT_TRUE(aircraft->maxWeapons > 0);
725 for (i = 0; i < aircraft->maxWeapons; i++)
726 ASSERT_TRUE(aircraft->weapons[i].delayNextShot == 0);
727
728 /* search a target */
729 UFO_CampaignRunUFOs(campaign, deltaTime);
730 ASSERT_TRUE(nullptr != ufo->aircraftTarget);
731
732 /* ensure that one hit will destroy the craft */
733 ufo->aircraftTarget->damage = 1;
734 srand(1);
735 /* don't take any pilot skill into account here */
736 OBJZERO(ufo->aircraftTarget->pilot->chr.score.skills);
737 UFO_CheckShootBack(campaign, ufo, ufo->aircraftTarget);
738
739 /* one projectile should be spawned */
740 ASSERT_EQ(ccs.numProjectiles, 1);
741 AIRFIGHT_CampaignRunProjectiles(campaign, deltaTime);
742 /* don't use mission pointer from here it might been removed */
743
744 /* target is destroyed */
745 ASSERT_TRUE(nullptr == ufo->aircraftTarget);
746
747 /* one aircraft less */
748 ASSERT_EQ(cnt - 1, AIR_BaseCountAircraft(base));
749
750 /* cleanup for the following tests */
751 E_DeleteAllEmployees(nullptr);
752
753 base->founded = false;
754}
755
757{
758 const vec2_t destination = { 10, 10 };
759 ufoType_t ufoTypes[UFO_MAX];
760 ASSERT_NE(0, UFO_GetAvailableUFOsForMission(INTERESTCATEGORY_INTERCEPT, ufoTypes, false));
761
762 base_t* base = CreateBase("unittestradar", destination);
764 aircraft_t* ufo = UFO_AddToGeoscape(ufoTypes[0], destination, mission);
765 Vector2Copy(destination, ufo->pos);
766 UFO_SendToDestination(ufo, destination);
767 ASSERT_TRUE(VectorEqual(ufo->pos, base->pos));
768 ASSERT_TRUE(VectorEqual(ufo->pos, ufo->pos));
769 /* to ensure that the UFOs are really detected when they are in range */
770 base->radar.ufoDetectionProbability = 1.0;
771 ASSERT_TRUE(RADAR_CheckUFOSensored(&base->radar, base->pos, ufo, false));
772
773 /* cleanup for the following tests */
774 E_DeleteAllEmployees(nullptr);
775
776 base->founded = false;
777}
778
780{
781 const nation_t* nation;
782 campaign_t* campaign;
783
784 nation = NAT_GetNationByID("europe");
785 ASSERT_TRUE(nullptr != nation);
786
787 campaign = GetCampaign();
788
789 NAT_HandleBudget(campaign);
791}
792
794{
795 campaign_t* campaign;
796
797 campaign = GetCampaign();
798
799 RS_InitTree(campaign, false);
800
801 BS_InitMarket(campaign);
802
803 CP_CampaignRunMarket(campaign);
805}
806
807TEST_F(CampaignTest, testSaveLoad)
808{
809 const vec2_t pos = {0, 0};
810 base_t* base;
811 campaign_t* campaign;
812
813 campaign = GetCampaign();
814
815 SAV_Init();
816
817 ccs.curCampaign = campaign;
818
819 Cvar_Set("save_compressed", "0");
820
821 base = CreateBase("unittestbase", pos);
822
823 {
824 ASSERT_TRUE(base->founded);
825 ASSERT_EQ(base->baseStatus, BASE_WORKING);
826
827 Cmd_ExecuteString("game_quicksave");
828 }
829 {
830 B_Destroy(base);
831
832 ASSERT_EQ(base->baseStatus, BASE_DESTROYED);
833
834 E_DeleteAllEmployees(nullptr);
835
836 B_SetName(base, "unittestbase2");
837 }
838#if 0
839 {
840 ResetCampaignData();
841
842 Cmd_ExecuteString("game_quickload");
843
845
846 ASSERT_EQ(base->baseStatus, BASE_WORKING);
847 ASSERT_STREQ(base->name, "unittestbase");
848
849 B_Destroy(base);
850
851 E_DeleteAllEmployees(nullptr);
852 }
853#endif
854 base->founded = false;
855}
856
857TEST_F(CampaignTest, testSaveMassEmployees)
858{
859 campaign_t* campaign = GetCampaign();
860
861 SAV_Init();
862
863 ccs.curCampaign = campaign;
864
865 Cvar_Set("save_compressed", "0");
866
867 const vec2_t pos = {0, 0};
868 base_t* base = CreateBase("unittestmassemployees", pos);
869
870 nation_t* nation = NAT_GetNationByID("europe");
871 ASSERT_TRUE(nullptr != nation);
872
873 const int employees = 10000;
874 for (int i = 0; i < employees; i++) {
876 if (CAP_GetFreeCapacity(base, CAP_EMPLOYEES) > 0) {
877 ASSERT_TRUE(E_HireEmployee(base, e));
878 }
879 }
880
881 Cmd_ExecuteString("game_quicksave");
882
883 /* cleanup for the following tests */
884 E_DeleteAllEmployees(nullptr);
885
886 base->founded = false;
887}
888
889TEST_F(CampaignTest, testLoadMassEmployees)
890{
891 Cmd_ExecuteString("game_quickload");
892
893 /* cleanup for the following tests */
894 E_DeleteAllEmployees(nullptr);
895}
896
897TEST_F(CampaignTest, testCampaignRun)
898{
899 const vec2_t destination = { 10, 10 };
900 const int days = 10;
901 const int seconds = days * DateTime::SECONDS_PER_DAY;
902
903 base_t* base = CreateBase("unittestcampaignrun", destination);
904
905 campaign_t* campaign = GetCampaign();
906
907 RS_InitTree(campaign, false);
908
909 BS_InitMarket(campaign);
910
911 int startDay = ccs.date.getDateAsDays();
912 for (int i = 0; i < seconds; i++) {
913 ccs.gameTimeScale = 1;
914 CP_CampaignRun(campaign, 1);
915 }
916 ASSERT_EQ(ccs.date.getDateAsDays() - startDay, days);
917
918 /* cleanup for the following tests */
919 E_DeleteAllEmployees(nullptr);
920
921 base->founded = false;
922}
923
925{
926 int i;
927 aircraft_t* ufo;
928 const char* error;
929
930 ccs.curCampaign = nullptr;
931 ASSERT_TRUE(SAV_GameLoad("unittest1", &error));
932 ASSERT_TRUE(nullptr != ccs.curCampaign);
933
934 i = 0;
935 ufo = nullptr;
936 while ((ufo = UFO_GetNextOnGeoscape(ufo)) != nullptr)
937 i++;
938
939 /* there should be one ufo on the geoscape */
940 ASSERT_EQ(i, 1);
941}
942
943TEST_F(CampaignTest, testDateHandling)
944{
945 DateTime date = DateTime(300, 300);
946
947 ccs.date = date;
948
949 ASSERT_TRUE(date <= ccs.date);
950 ASSERT_FALSE(ccs.date > date);
951
952 date = DateTime(299, 310);
953
954 ASSERT_TRUE(date <= ccs.date);
955 ASSERT_TRUE(ccs.date > date);
956
957 date = DateTime(301, 0);
958
959 ASSERT_FALSE(date <= ccs.date);
960 ASSERT_FALSE(ccs.date > date);
961
962 date = DateTime(300, 299);
963
964 ASSERT_TRUE(date <= ccs.date);
965 ASSERT_TRUE(ccs.date > date);
966
967 date = DateTime(300, 301);
968
969 ASSERT_FALSE(date <= ccs.date);
970 ASSERT_FALSE(ccs.date > date);
971}
972
976TEST_F(CampaignTest, testCampaignDateHandling)
977{
978 campaign_t* campaign;
979 base_t* base;
980 const vec2_t destination = { 10, 10 };
981
982 base = CreateBase("unittestcampaigntime", destination);
983
984 campaign = GetCampaign();
985
986 RS_InitTree(campaign, false);
987
988 BS_InitMarket(campaign);
989
990 /* one hour till month change */
991 ccs.date = DateTime(30, 23 * 60 * 60);
993 ccs.gameLapse = 7;
994 ccs.paid = true;
996 CP_CampaignRun(campaign, 1);
997 ASSERT_FALSE(ccs.paid);
998 ASSERT_TRUE(CP_IsTimeStopped());
999
1000 /* cleanup for the following tests */
1001 E_DeleteAllEmployees(nullptr);
1002
1003 base->founded = false;
1004}
1005
1006TEST_F(CampaignTest, testHospital)
1007{
1008 base_t* base;
1009 const vec2_t destination = { 10, 10 };
1010 int i, n;
1011
1012 base = CreateBase("unittesthospital", destination);
1013
1014 n = 0;
1015 /* hurt all employees */
1016 for (i = 0; i < MAX_EMPL; i++) {
1018 E_Foreach(type, employee) {
1019 if (!employee->isHired())
1020 continue;
1021 employee->chr.HP = employee->chr.maxHP - 10;
1022 n++;
1023 }
1024 }
1025 ASSERT_NE(n, 0);
1026
1028
1029 for (i = 0; i < MAX_EMPL; i++) {
1031 E_Foreach(type, employee) {
1032 if (!employee->isHired())
1033 continue;
1034 ASSERT_NE(employee->chr.HP, employee->chr.maxHP - 10) << employee->chr.HP << "/" << employee->chr.maxHP;
1035 }
1036 }
1037
1038 /* cleanup for the following tests */
1039 E_DeleteAllEmployees(nullptr);
1040
1041 base->founded = false;
1042}
1043
1044TEST_F(CampaignTest, testBuildingConstruction)
1045{
1046 const vec2_t pos = {0, 0};
1047 int x, y;
1048 base_t* base;
1049 const building_t* buildingTemplate;
1050 building_t* entrance, *building1, *building2;
1051
1052 /* day 0 has special meaning! */
1053 /* if building->startTime is 0 no buildTime checks done! */
1054 ccs.date += DateTime(1, 0);
1055 base = CreateBase("unittestbuildingconstruction1", pos);
1056 ASSERT_TRUE(nullptr != base);
1057 base = CreateBase("unittestbuildingconstruction2", pos);
1058 ASSERT_TRUE(nullptr != base);
1059
1060 /* base should have exactly one building: entrance */
1061 ASSERT_EQ(ccs.numBuildings[base->idx], 1);
1062 entrance = &ccs.buildings[base->idx][0];
1063
1064 /* try to build powerplant that is not connected */
1065 buildingTemplate = B_GetBuildingTemplate("building_powerplant");
1066 ASSERT_TRUE(nullptr != buildingTemplate);
1067
1068 /* select position */
1069 x = entrance->pos[0];
1070 y = entrance->pos[1];
1071 ASSERT_EQ(entrance, base->map[y][x].building);
1072 if (x >= 2)
1073 x -= 2;
1074 else
1075 x += 2;
1076 /* reset blocked status if set */
1077 base->map[y][x].blocked = false;
1078 /* try to build (should fail) */
1079 building1 = B_BuildBuilding(base, buildingTemplate, x, y);
1080 ASSERT_TRUE(nullptr == building1);
1081
1082 /* next to the entrance it should succeed */
1083 x = (x + entrance->pos[0]) /2;
1084 base->map[y][x].blocked = false;
1085 building1 = B_BuildBuilding(base, buildingTemplate, x, y);
1086 ASSERT_TRUE(nullptr != building1);
1087
1088 /* try to build to first pos again (still fail, conecting building not ready) */
1089 if (x < entrance->pos[0])
1090 x--;
1091 else
1092 x++;
1093 building2 = B_BuildBuilding(base, buildingTemplate, x, y);
1094 ASSERT_TRUE(nullptr == building2);
1095 /* roll time one day before building finishes */
1096 ccs.date += DateTime(building1->buildTime - 1, 0);
1098 /* building should be under construction */
1099 ASSERT_EQ(building1->buildingStatus, B_STATUS_UNDER_CONSTRUCTION);
1100 /* step a day */
1101 ccs.date += DateTime(1, 0);
1103 /* building should be ready */
1104 ASSERT_EQ(building1->buildingStatus, B_STATUS_WORKING);
1105
1106 /* try build other building (now it should succeed) */
1107 building2 = B_BuildBuilding(base, buildingTemplate, x, y);
1108 ASSERT_TRUE(nullptr != building2);
1109
1110 /* try to destroy the second (should success) */
1111 ASSERT_TRUE(B_BuildingDestroy(building2));
1112 /* rebuild */
1113 building2 = B_BuildBuilding(base, buildingTemplate, x, y);
1114 ASSERT_TRUE(nullptr != building2);
1115
1116 /* try to destroy the first (should fail) */
1117 ASSERT_FALSE(B_BuildingDestroy(building1));
1118 /* build up the second */
1119 ccs.date += DateTime(building2->buildTime, 0);
1121 /* try to destroy the first (should fail) */
1122 ASSERT_FALSE(B_BuildingDestroy(building1));
1123 /* try to destroy the second (should succeess) */
1124 ASSERT_TRUE(B_BuildingDestroy(building2));
1125 /* try to destroy the first (should succeed) */
1126 ASSERT_TRUE(B_BuildingDestroy(building1));
1127
1128 /* cleanup for the following tests */
1129 E_DeleteAllEmployees(nullptr);
1130
1131 base->founded = false;
1132}
1133
1134/* https://sourceforge.net/tracker/index.php?func=detail&aid=3090011&group_id=157793&atid=805242 */
1136{
1137 const char* error = nullptr;
1138 bool success;
1139
1140 success = SAV_GameLoad("3090011", &error);
1141 ASSERT_TRUE(success) << error;
1142}
1143
1144static bool skipTest (const mapDef_t* md)
1145{
1146 const char* map = md->id;
1147 return Q_streq(map, "baseattack") || Q_streq(map, "rescue") || Q_streq(map, "alienbase");
1148}
1149
1150TEST_F(CampaignTest, testTerrorMissions)
1151{
1152 int numUfoTypes;
1153 ufoType_t ufoTypes[UFO_MAX];
1154 mapDef_t* md;
1155 int i;
1156
1157 /* Set overall interest level so every UFO can be used for missions */
1158 const short ufoIdsNum = Com_GetUfoIdsNum();
1159 for (i = 0; i < ufoIdsNum; i++) {
1160 ufoType_t ufoType = i;
1161 const aircraft_t* ufo = UFO_GetByType(ufoType);
1162
1163 if (!ufo)
1164 continue;
1165
1166 ccs.overallInterest = std::max(ccs.overallInterest, ufo->ufoInterestOnGeoscape);
1167 }
1168
1169 /* Search without UFO */
1170 LIST_Foreach(ccs.cities, city_t, city) {
1171 mission_t mission;
1172 OBJZERO(mission);
1173 ASSERT_TRUE(CP_ChooseMap(&mission, city->pos)) << "could not find a map for city " << city->id;
1174 }
1175
1176 /* Search with UFOs available for Terror missions */
1177 numUfoTypes = UFO_GetAvailableUFOsForMission(INTERESTCATEGORY_TERROR_ATTACK, ufoTypes, false);
1178 ASSERT_NE(0, numUfoTypes);
1179 for (i = 0; i < numUfoTypes; i++) {
1180 ufoType_t ufoType = i;
1181 mission_t mission;
1182 aircraft_t* ufo = UFO_AddToGeoscape(ufoTypes[ufoType], nullptr, &mission);
1183
1184 OBJZERO(mission);
1185 mission.ufo = ufo;
1186 ASSERT_TRUE(nullptr != ufo);
1187 ufo->mission = &mission;
1188
1189 LIST_Foreach(ccs.cities, city_t, city) {
1190 mission.mapDef = nullptr;
1191#ifdef TEST_BIGUFOS
1192 ASSERT_TRUE(CP_ChooseMap(&mission, city->pos)) << "could not find map for city " << city->id << " with ufo: " << ufo->id;
1193#else
1194 CP_ChooseMap(&mission, city->pos);
1195#endif
1196 }
1197
1199 }
1200
1202 /* skip mapDefs that were used */
1203 if (md->timesAlreadyUsed > 0)
1204 continue;
1205 /* skip special mapDefs */
1206 if (skipTest(md))
1207 continue;
1208 /* skip mapDefs which don't support UFO types that do terror missions */
1209 if (!LIST_IsEmpty(md->ufos)) {
1210 bool found = false;
1211 for (i = 0; i < numUfoTypes; i++) {
1212 ufoType_t ufoType = i;
1213 const aircraft_t* ufo = UFO_GetByType(ufoTypes[ufoType]);
1214
1215 if (!ufo)
1216 continue;
1217
1218 if (LIST_ContainsString(md->ufos, ufo->id)) {
1219 found = true;
1220 break;
1221 }
1222 }
1223 if (!found)
1224 continue;
1225 }
1226 ASSERT_TRUE(va("%s wasn't used", md->id));
1227 }
1228}
1229
1230TEST_F(CampaignTest, testRandomPosMissions)
1231{
1232 const mapDef_t* md;
1233
1235 if (!skipTest(md)) {
1236 mission_t mission;
1237 bool result;
1238 OBJZERO(mission);
1239 result = CP_GetRandomPosOnGeoscapeWithParameters(mission.pos, md->terrains, md->cultures, md->populations, nullptr);
1240 ASSERT_TRUE(result) << "could not find a mission for mapdef " << md->id;
1241 }
1242 }
1243}
1244
1246static void testEventTrigger_f (void)
1247{
1249}
1250
1251TEST_F(CampaignTest, testEventTrigger)
1252{
1253 testEventTriggerCalled = false;
1254 for (int i = 0; i < 60; i++) {
1256 ccs.date += DateTime(1, 0);
1257 }
1258 Cmd_AddCommand("test_eventtrigger", testEventTrigger_f);
1259 campaignTriggerEvent_t* event = &ccs.campaignTriggerEvents[ccs.numCampaignTriggerEvents++];
1260 OBJZERO(*event);
1261 event->active = true;
1262 event->type = UFO_DETECTION;
1263 event->id = Mem_StrDup("test_eventtrigger");
1264 event->command = Mem_StrDup("test_eventtrigger");
1265 event->require = Mem_StrDup("ufo[craft_ufo_harvester]");
1266 CP_TriggerEvent(UFO_DETECTION, "craft_ufo_harvester");
1267 ASSERT_TRUE(testEventTriggerCalled);
1268 testEventTriggerCalled = false;
1270 ASSERT_FALSE(testEventTriggerCalled);
1271 event->once = true;
1272 CP_TriggerEvent(UFO_DETECTION, "craft_ufo_harvester");
1273 ASSERT_TRUE(testEventTriggerCalled);
1274 testEventTriggerCalled = false;
1275 CP_TriggerEvent(UFO_DETECTION, "craft_ufo_harvester");
1276 ASSERT_FALSE(testEventTriggerCalled);
1277 --ccs.numCampaignTriggerEvents;
1278 Cmd_RemoveCommand("test_eventtrigger");
1279}
1280
1281TEST_F(CampaignTest, testAssembleMap)
1282{
1283 const int expected = 22;
1284 const int maxSize = BASE_SIZE * BASE_SIZE;
1285 ASSERT_TRUE(maxSize >= expected);
1286
1287 const vec2_t destination = { 10, 10 };
1288 base_t* base = CreateBase("unittestassemble", destination);
1289 ASSERT_TRUE(nullptr != base);
1290 char maps[2048];
1291 char coords[2048];
1292
1293 ASSERT_TRUE(B_AssembleMap(maps, sizeof(maps), coords, sizeof(coords), base));
1294 const char* str = coords;
1295 int coordsAmount = 0;
1296 do {
1297 Com_Parse(&str);
1298 if (str != nullptr)
1299 ++coordsAmount;
1300 } while (str != nullptr);
1301
1302 str = maps;
1303 int mapsAmount = 0;
1304 do {
1305 Com_Parse(&str);
1306 if (str != nullptr)
1307 ++mapsAmount;
1308 } while (str != nullptr);
1309
1310 /* we have three components, x, y and z for the coordinates */
1311 ASSERT_EQ(coordsAmount / 3, expected) << "coords have " << coordsAmount << " entries: '" << coords << "'";
1312 ASSERT_EQ(mapsAmount, expected) << "maps have " << mapsAmount << " entries: '"<< maps << "'";
1313}
1314
1315TEST_F(CampaignTest, testGeoscapeMaps)
1316{
1317 const char* types[] = {"terrain", "culture", "population", "nations", nullptr};
1318 for (int i = 0; i < ccs.numCampaigns; i++) {
1319 const campaign_t& c = ccs.campaigns[i];
1320 int refW = -1;
1321 int refH = -1;
1322
1323 for (const char **t = types; *t; ++t) {
1324 const char *image = va("pics/geoscape/%s_%s", c.map, *t);
1325 SDL_Surface *surf = Img_LoadImage(image);
1326 ASSERT_TRUE(surf != nullptr);
1327 const int w = surf->w;
1328 const int h = surf->h;
1329 if (refH == -1) {
1330 refH = h;
1331 refW = w;
1332 }
1333 SDL_FreeSurface(surf);
1334 ASSERT_EQ(refH, h);
1335 ASSERT_EQ(refW, w);
1336 }
1337 }
1338}
1339
1340TEST_F(CampaignTest, testAlienBaseAtStart)
1341{
1342 bool exists = AB_Exists();
1344 ASSERT_FALSE(exists);
1345 ASSERT_EQ(0, count);
1346}
1347
1348TEST_F(CampaignTest, testAlienBaseBuild)
1349{
1350 const vec2_t pos = {1, -89};
1351
1352 alienBase_t* alienBase = AB_BuildBase(pos);
1353
1354 ASSERT_NE(nullptr, alienBase);
1355 ASSERT_TRUE(AB_Exists());
1356 ASSERT_EQ(1, AB_GetAlienBaseNumber());
1357 ASSERT_EQ(50.f, alienBase->stealth);
1358 ASSERT_EQ(0, alienBase->supply);
1359 ASSERT_EQ(1, alienBase->pos[0]);
1360 ASSERT_EQ(-89, alienBase->pos[1]);
1361}
1362
1363TEST_F(CampaignTest, testAlienBaseSearchedByNationsFindBase)
1364{
1365 const vec2_t phalanxPos = {0, 0};
1366 base_t* base= CreateBase("PHALANX", phalanxPos, true);
1367 /* @TODO: We need a function to return a position within a particular nation that can
1368 be nullptr nation. For now this position should be around Antartica with no nation */
1369 const vec2_t alienPos = {0, -89};
1370 alienBase_t* alienBase = AB_BuildBase(alienPos);
1371 alienBase->stealth = 1.0f;
1372 alienBase->supply = 2;
1373
1375
1376 ASSERT_NE(nullptr, alienBase);
1377 ASSERT_GT(0.0f, alienBase->stealth);
1378 mission_t* mission = MIS_GetByIdx(1);
1379 ASSERT_NE(nullptr, mission);
1380 ASSERT_EQ(alienBase, mission->data.alienBase);
1381}
DateTime class definition.
void GAME_InitStartup(void)
Definition cl_game.cpp:1669
static const int TAG_INVENTORY
Definition cl_game.cpp:880
static const inventoryImport_t inventoryImport
Definition cl_game.cpp:898
Shared game type headers.
void CL_InitLua(void)
Initializes the ui-lua interfacing environment.
Definition cl_lua.cpp:130
memPool_t * vid_imagePool
Definition cl_main.cpp:88
void CL_SetClientState(connstate_t state)
Sets the client state.
Definition cl_main.cpp:1015
client_static_t cls
Definition cl_main.cpp:83
memPool_t * cl_genericPool
Definition cl_main.cpp:86
void R_FontInit(void)
Definition r_font.cpp:716
mapDef_t * Com_GetMapDefinitionByID(const char *mapDefID)
Definition scripts.cpp:3598
@ ca_disconnected
Definition cl_shared.h:77
#define MapDef_ForeachSingleplayerCampaign(var)
Definition cl_shared.h:84
static void TearDownTestCase()
static void SetUpTestCase()
Class describing a point of time.
Definition DateTime.h:31
static const int SECONDS_PER_DAY
Definition DateTime.h:43
Item cargo class.
Definition itemcargo.h:41
Primary header for client.
void Cmd_ExecuteString(const char *text,...)
A complete command line has been parsed, so try to execute it.
Definition cmd.cpp:1007
void Cmd_RemoveCommand(const char *cmdName)
Removes a command from script interface.
Definition cmd.cpp:786
void Cmd_Dummy_f(void)
Dummy binding if you don't want unknown commands forwarded to the server.
Definition cmd.cpp:1083
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition cmd.cpp:744
csi_t csi
Definition common.cpp:39
memPool_t * com_genericPool
Definition common.cpp:72
void AIR_DeleteAircraft(aircraft_t *aircraft)
Removes an aircraft from its base and the game.
int AIR_BaseCountAircraft(const base_t *base)
Returns the number of aircraft on the given base.
aircraft_t * AIR_NewAircraft(base_t *base, const aircraft_t *aircraftTemplate)
Places a new aircraft in the given base.
bool AIR_IsAircraftOnGeoscape(const aircraft_t *aircraft)
Checks whether given aircraft is on geoscape.
int AIR_GetTeamSize(const aircraft_t *aircraft)
Counts the number of soldiers in given aircraft.
const aircraft_t * AIR_GetAircraft(const char *name)
Searches the global array of aircraft types for a given aircraft.
aircraft_t * AIR_GetFirstFromBase(const base_t *b)
Iterates through the aircraft of a base.
#define AIR_Foreach(var)
iterates trough all aircraft
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
@ AIR_IDLE
void AIRFIGHT_CampaignRunProjectiles(const campaign_t *campaign, int dt)
Update values of projectiles.
void INT_ResetAlienInterest(void)
Initialize alien interest values and mission cycle.
Alien interest header.
@ INTERESTCATEGORY_RECON
@ INTERESTCATEGORY_TERROR_ATTACK
@ INTERESTCATEGORY_INTERCEPT
int AB_GetAlienBaseNumber(void)
Check number of alien bases.
alienBase_t * AB_BuildBase(const vec2_t pos)
Build a new alien base.
void AB_BaseSearchedByNations(void)
Nations help in searching alien base.
#define AB_Exists()
void AM_Go(mission_t *mission, aircraft_t *aircraft, const campaign_t *campaign, const battleParam_t *battleParameters, missionResults_t *results)
Handles the auto mission.
Header file for single player automatic (quick, simulated) missions, without going to the battlescape...
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
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
int B_GetInstallationLimit(void)
Counts the actual installation count limit.
Definition cp_base.cpp:1153
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
void B_UpdateBuildingConstructions(void)
Updates base data.
Definition cp_base.cpp:2009
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
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
@ BASE_WORKING
Definition cp_base.h:64
@ BASE_DESTROYED
Definition cp_base.h:65
#define B_AtLeastOneExists()
Definition cp_base.h:55
building_t * B_GetBuildingTemplate(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
@ B_WORKSHOP
Definition cp_building.h:56
@ B_STATUS_UNDER_CONSTRUCTION
Definition cp_building.h:33
@ B_STATUS_WORKING
Definition cp_building.h:36
memPool_t * cp_campaignPool
void CP_ResetCampaignData(void)
Will clear most of the parsed singleplayer data.
void CP_CampaignRun(campaign_t *campaign, float secondsSinceLastFrame)
Called every frame when we are in geoscape view.
campaign_t * CP_GetCampaign(const char *name)
Returns the campaign pointer from global campaign array.
void CP_UpdateCredits(int credits)
Sets credits and update mn_credits cvar.
cvar_t * cp_missiontest
ccs_t ccs
Header file for single player campaign control.
void CP_ParseCampaignData(void)
Read the data for campaigns.
Definition cp_parse.cpp:641
#define MAX_CREDITS
@ MAPTYPE_TERRAIN
Definition cp_campaign.h:93
void CP_ReadCampaignData(const campaign_t *campaign)
Definition cp_parse.cpp:692
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
@ CAP_ITEMS
Definition cp_capacity.h:32
@ CAP_EMPLOYEES
Definition cp_capacity.h:31
@ CAP_AIRCRAFT_SMALL
Definition cp_capacity.h:29
bool E_DeleteEmployee(Employee *employee)
Removes the employee completely from the game (buildings + global list).
void E_InitialEmployees(const campaign_t *campaign)
Create initial hireable employees.
Employee * E_CreateEmployee(employeeType_t type, const nation_t *nation, const ugv_t *ugvType)
Creates an entry of a new employee in the global list and assignes it to no building/base.
void E_DeleteAllEmployees(base_t *base)
Removes all employees completely from the game (buildings + global list) from a given base.
int E_CountHired(const base_t *const base, employeeType_t type)
Counts hired employees of a given type in a given base.
bool E_HireEmployee(base_t *base, Employee *employee)
Hires the employee in a base.
int E_CountUnhired(employeeType_t type)
Counts unhired employees of a given type in a given base.
employeeType_t
The types of employees.
Definition cp_employee.h:30
@ EMPL_SOLDIER
Definition cp_employee.h:31
@ MAX_EMPL
Definition cp_employee.h:36
@ EMPL_ROBOT
Definition cp_employee.h:35
@ EMPL_WORKER
Definition cp_employee.h:33
#define E_Foreach(employeeType, var)
void CP_TriggerEvent(campaignTriggerEventType_t type, const void *userdata)
Triggers a campaign event with a special type.
Definition cp_event.cpp:310
@ UFO_DETECTION
Definition cp_event.h:80
@ NEW_DAY
Definition cp_event.h:79
void GEO_Init(const char *map)
bool CP_GetRandomPosOnGeoscapeWithParameters(vec2_t pos, const linkedList_t *terrainTypes, const linkedList_t *cultureTypes, const linkedList_t *populationTypes, const linkedList_t *nations)
Determines a random position on geoscape that fulfills certain criteria given via parameters.
const byte * GEO_GetColor(const vec2_t pos, mapType_t type, bool *coast)
Returns the color value from geoscape of a certain mask (terrain, culture or population) at a given p...
void GEO_Shutdown(void)
Header for Geoscape management.
#define MapIsWater(color)
Definition cp_geoscape.h:32
void HOS_HospitalRun(void)
Checks health status of all employees in all bases.
Header file for hospital related stuff.
installation_t * INS_Build(const installationTemplate_t *installationTemplate, const vec2_t pos, const char *name)
Build a new installation.
const installationTemplate_t * INS_GetInstallationTemplateByType(installationType_t type)
Returns the installation Template for a given installation type.
void INS_UpdateInstallationData(void)
Check if some installation are build.
@ INSTALLATION_UFOYARD
#define MAX_INSTALLATIONS_PER_BASE
void BS_InitMarket(const campaign_t *campaign)
sets market prices at start of the game
void CP_CampaignRunMarket(campaign_t *campaign)
make number of items change every day.
void CP_InterceptNextStage(mission_t *mission)
Determine what action should be performed when a Intercept mission stage ends.
Campaign mission headers.
void CP_CreateBattleParameters(mission_t *mission, battleParam_t *param, const aircraft_t *aircraft)
Create parameters needed for battle. This is the data that is used for starting the tactical part of ...
mission_t * CP_CreateNewMission(interestCategory_t category, bool beginNow)
Create a new mission of given category.
bool CP_ChooseMap(mission_t *mission, const vec2_t pos)
Choose a map for given mission.
mission_t * MIS_GetByIdx(int id)
Find mission corresponding to idx.
Campaign missions headers.
@ WON
Definition cp_missions.h:57
@ STAGE_NOT_ACTIVE
Definition cp_missions.h:35
@ STAGE_COME_FROM_ORBIT
Definition cp_missions.h:36
@ STAGE_INTERCEPT
Definition cp_missions.h:47
void NAT_HandleBudget(const campaign_t *campaign)
Update the nation data from all parsed nation each month.
nation_t * NAT_GetNationByID(const char *nationID)
Return a nation-pointer by the nations id.
Definition cp_nation.cpp:64
Nation code.
Functions to generate and render overlay for geoscape.
void PR_ProductionRun(void)
Checks whether an item is finished.
int PR_WorkersAvailable(const base_t *base)
Returns the numer of workers available to produce an item.
production_t * PR_QueueNew(base_t *base, const productionData_t *data, signed int amount)
Add a new item to the bottom of the production queue.
int PR_GetRemainingMinutes(const production_t *prod)
Calculates the remaining time for a technology in minutes.
int PR_GetRemainingHours(const production_t *prod)
Calculates the remaining hours for a technology.
@ PRODUCTION_TYPE_DISASSEMBLY
Definition cp_produce.h:38
@ PRODUCTION_TYPE_ITEM
Definition cp_produce.h:36
@ PRODUCTION_TYPE_AIRCRAFT
Definition cp_produce.h:37
#define PR_SetData(dataPtr, typeVal, ptr)
Definition cp_produce.h:80
bool RADAR_CheckUFOSensored(radar_t *radar, const vec2_t posRadar, const aircraft_t *ufo, bool detected)
Check if the specified UFO is inside the sensor range of the given radar.
Definition cp_radar.cpp:408
void RS_MarkOneResearchable(technology_t *tech)
Marks one tech as researchable.
technology_t * RS_GetTechForItem(const objDef_t *item)
Returns technology entry for an item.
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
void RS_AssignScientist(technology_t *tech, base_t *base, Employee *employee)
Assigns scientist to the selected research-project.
int RS_ResearchRun(void)
Checks the research status.
void RS_MarkResearchable(const base_t *base, bool init)
Marks all the techs that can be researched. Automatically researches 'free' techs such as ammo for a ...
void RS_InitTree(const campaign_t *campaign, bool load)
Gets all needed names/file-paths/etc... for each technology entry. Should be executed after the parsi...
@ RS_FINISH
Definition cp_research.h:44
@ RS_RUNNING
Definition cp_research.h:42
bool SAV_GameLoad(const char *file, const char **error)
Loads the given savegame from an xml File.
Definition cp_save.cpp:152
void SAV_Init(void)
Register all save-subsystems and init some cvars and commands.
Definition cp_save.cpp:410
void CP_UpdateTime(void)
Updates date/time and timescale (=timelapse) on the geoscape menu.
Definition cp_time.cpp:104
bool CP_IsTimeStopped(void)
Check if time is stopped.
Definition cp_time.cpp:139
Campaign geoscape time header.
transfer_t * TR_TransferStart(base_t *srcBase, transfer_t &transData)
Starts a transfer.
void TR_TransferRun(void)
Checks whether given transfer should be processed.
static transfer_t tr
void UFO_CampaignRunUFOs(const campaign_t *campaign, int deltaTime)
Make the UFOs run.
Definition cp_ufo.cpp:601
void UFO_SendToDestination(aircraft_t *ufo, const vec2_t dest)
Make the specified UFO go to destination.
Definition cp_ufo.cpp:562
void UFO_CheckShootBack(const campaign_t *campaign, aircraft_t *ufo, aircraft_t *phalanxAircraft)
Check if the ufo can shoot back at phalanx aircraft.
Definition cp_ufo.cpp:578
const aircraft_t * UFO_GetByType(const ufoType_t type)
Get the aircraft template for a given UFO type.
Definition cp_ufo.cpp:109
aircraft_t * UFO_AddToGeoscape(ufoType_t ufoType, const vec2_t destination, mission_t *mission)
Add a UFO to geoscape.
Definition cp_ufo.cpp:773
aircraft_t * UFO_GetNextOnGeoscape(aircraft_t *lastUFO)
Definition cp_ufo.cpp:66
int UFO_GetAvailableUFOsForMission(const interestCategory_t missionType, ufoType_t *ufoTypes, bool checkInterest)
Fill an array with available UFOs for the mission type.
Definition cp_ufo.cpp:153
void UFO_RemoveFromGeoscape(aircraft_t *ufo)
Remove the specified ufo from geoscape.
Definition cp_ufo.cpp:817
storedUFO_t * US_StoreUFO(const aircraft_t *ufoTemplate, installation_t *installation, DateTime &date, float condition)
Adds an UFO to the storage.
void UR_ProcessActive(void)
Function to process active recoveries.
@ SUFO_STORED
@ SUFO_RECOVERED
cvar_t * Cvar_Set(const char *varName, const char *value,...)
Sets a cvar value.
Definition cvar.cpp:615
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition cvar.cpp:342
SDL_Surface * Img_LoadImage(char const *name)
Loads the specified image from the game filesystem into an SDL_Surface.
Definition images.cpp:488
Image loading and saving functions.
const objDef_t * INVSH_GetItemByID(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn't found.
voidpf void uLong size
Definition ioapi.h:42
Item cargo class header.
int LIST_Count(const linkedList_t *list)
Definition list.cpp:344
bool LIST_IsEmpty(const linkedList_t *list)
Checks whether the given list is empty.
Definition list.cpp:335
const linkedList_t * LIST_ContainsString(const linkedList_t *list, const char *string)
Searches for the first occurrence of a given string.
Definition list.cpp:73
#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
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_CreatePool(name)
Definition mem.h:32
#define Mem_FreeTag(pool, tagNum)
Definition mem.h:36
#define Mem_PoolAlloc(size, pool, tagNum)
Definition mem.h:41
#define Mem_StrDup(in)
Definition mem.h:48
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition parse.cpp:107
Shared parsing functions.
QGL_EXTERN void(APIENTRY *qglActiveTexture)(GLenum texture)
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN GLsizei const GLvoid * data
Definition r_gl.h:89
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
rstate_t r_state
Definition r_main.cpp:48
void Com_ParseScripts(bool onlyServer)
Definition scripts.cpp:3619
const ugv_t * Com_GetUGVByID(const char *ugvID)
Searches an UGV definition by a given script id and returns the pointer to the global data.
Definition scripts.cpp:3381
short Com_GetUfoIdsNum(void)
Definition scripts.cpp:571
#define UFO_MAX
Definition scripts.h:146
short ufoType_t
Definition scripts.h:145
#define Q_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
An aircraft with all it's data.
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
struct aircraft_s * aircraftTarget
int ufoInterestOnGeoscape
struct base_s * homebase
aircraftStatus_t status
struct mission_s * mission
ufoType_t ufotype
struct aircraft_s * tpl
struct technology_s * tech
Alien Base.
A base with all it's data.
Definition cp_base.h:84
struct radar_s radar
Definition cp_base.h:106
bool founded
Definition cp_base.h:90
baseBuildingTile_t map[BASE_SIZE][BASE_SIZE]
Definition cp_base.h:87
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
equipDef_t storage
Definition cp_base.h:112
building_t * building
Definition cp_base.h:69
A building with all it's data.
Definition cp_building.h:73
buildingStatus_t buildingStatus
Definition cp_building.h:94
char map[MAX_VAR]
City definition.
Definition cp_nation.h:70
int numItems[MAX_OBJDEFS]
Definition inv_shared.h:608
A installation with all it's data.
const installationTemplate_t * installationTemplate
int timesAlreadyUsed
Definition q_shared.h:490
linkedList_t * ufos
Definition q_shared.h:491
char * id
Definition q_shared.h:463
linkedList_t * terrains
Definition q_shared.h:486
linkedList_t * cultures
Definition q_shared.h:488
linkedList_t * populations
Definition q_shared.h:487
mission definition
Definition cp_missions.h:86
aircraft_t * ufo
mapDef_t * mapDef
Definition cp_missions.h:89
missionStage_t stage
Definition cp_missions.h:99
vec2_t pos
union mission_t::missionData_t data
bool posAssigned
Structure with mission info needed to create results summary at menu won.
Definition cp_missions.h:61
missionState_t state
Definition cp_missions.h:63
Nation definition.
Definition cp_nation.h:46
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
Holds all information for the production of one item-type.
Definition cp_produce.h:60
Structure for stored UFOs.
struct components_s * comp
storedUFOStatus_t status
This is the technology parsed from research.ufo.
researchStatus_t statusResearch
struct base_s * base
bool statusResearchable
Transfer information (they are being stored in ccs.transfers).
Definition cp_transfer.h:33
class DateTime event
Definition cp_transfer.h:36
Defines a type of UGV/Robot.
Definition chr_shared.h:245
int Sys_Milliseconds(void)
static void ResetInventoryList(void)
static bool testEventTriggerCalled
static void * AllocInventoryMemory(size_t size)
static base_t * CreateBase(const char *name, const vec2_t pos, bool fillBase=false)
static void testEventTrigger_f(void)
static void FreeAllInventory(void)
TEST_F(CampaignTest, testAircraftHandling)
static installation_t * CreateInstallation(const char *name, const vec2_t pos)
static bool skipTest(const mapDef_t *md)
static campaign_t * GetCampaign(void)
static void FreeInventory(void *data)
void TEST_Shutdown(void)
void TEST_Init(void)
vec_t vec2_t[2]
Definition ufotypes.h:38
void UI_Init(void)
Definition ui_main.cpp:278
alienBase_t * alienBase
Definition cp_missions.h:95
#define VectorEqual(a, b)
Definition vector.h:65
#define Vector2Set(v, x, y)
Definition vector.h:61
#define Vector2Copy(src, dest)
Definition vector.h:52