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