UFO: Alien Invasion
Doxygen documentation generating
cp_mapfightequip.cpp
Go to the documentation of this file.
1 
8 /*
9 Copyright (C) 2002-2023 UFO: Alien Invasion.
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26 
27 #include "../../cl_shared.h"
28 #include "cp_campaign.h"
29 #include "cp_missions.h"
30 #include "cp_mapfightequip.h"
31 #include "cp_ufo.h"
32 #include "save/save_fightequip.h"
33 
34 #define UFO_RELOAD_DELAY_MULTIPLIER 2
35 #define AIRCRAFT_RELOAD_DELAY_MULTIPLIER 2
36 #define BASE_RELOAD_DELAY_MULTIPLIER 2
37 #define INSTALLATION_RELOAD_DELAY_MULTIPLIER 2
38 
45 {
46  static technology_t* techList[MAX_TECHNOLOGIES];
47  int j = 0;
48 
49  for (int i = 0; i < cgi->csi->numODs; i++) {
50  const objDef_t* aircraftitem = INVSH_GetItemByIDX(i);
51  if (aircraftitem->craftitem.type == type) {
52  technology_t* tech = RS_GetTechForItem(aircraftitem);
53  assert(j < MAX_TECHNOLOGIES);
54  techList[j] = tech;
55  j++;
56  }
57  /* j+1 because last item has to be nullptr */
58  if (j + 1 >= MAX_TECHNOLOGIES) {
59  cgi->Com_Printf("AII_GetCraftitemTechsByType: MAX_TECHNOLOGIES limit hit.\n");
60  break;
61  }
62  }
63  /* terminate the list */
64  techList[j] = nullptr;
65  return techList;
66 }
67 
75 {
76  assert(od);
77 
78  if (od->size < 50)
79  return ITEM_LIGHT;
80  else if (od->size < 100)
81  return ITEM_MEDIUM;
82  else
83  return ITEM_HEAVY;
84 }
85 
92 bool AIM_SelectableCraftItem (const aircraftSlot_t* slot, const technology_t* tech)
93 {
94  const objDef_t* item;
95 
96  if (!slot)
97  return false;
98 
99  if (!RS_IsResearched_ptr(tech))
100  return false;
101 
102  item = INVSH_GetItemByID(tech->provides);
103  if (!item)
104  return false;
105 
106  if (item->craftitem.type >= AC_ITEM_AMMO) {
107  const objDef_t* weapon = slot->item;
108  int k;
109  if (slot->nextItem != nullptr)
110  weapon = slot->nextItem;
111 
112  if (weapon == nullptr)
113  return false;
114 
115  /* Is the ammo is usable with the slot */
116  for (k = 0; k < weapon->numAmmos; k++) {
117  const objDef_t* usable = weapon->ammos[k];
118  if (usable && item->idx == usable->idx)
119  break;
120  }
121  if (k >= weapon->numAmmos)
122  return false;
123  }
124 
126  if (slot->type >= AC_ITEM_AMMO) {
129  if (!slot->nextItem && item->weapons[0] != slot->item)
130  return false;
131 
132  /* are we trying to change ammos for nextItem? */
133  if (slot->nextItem && item->weapons[0] != slot->nextItem)
134  return false;
135  }
136 
137  /* you can install an item only if its weight is small enough for the slot */
138  if (AII_GetItemWeightBySize(item) > slot->size)
139  return false;
140 
141  /* you can't install an item that you don't possess
142  * virtual items don't need to be possessed
143  * installations always have weapon and ammo */
144  if (slot->aircraft) {
145  if (!B_BaseHasItem(slot->aircraft->homebase, item))
146  return false;
147  } else if (slot->base) {
148  if (!B_BaseHasItem(slot->base, item))
149  return false;
150  }
151 
152  /* you can't install an item that does not have an installation time (alien item)
153  * except for ammo which does not have installation time */
154  if (item->craftitem.installationTime == -1 && slot->type < AC_ITEM_AMMO)
155  return false;
156 
157  return true;
158 }
159 
166 bool AIM_PilotAssignedAircraft (const base_t* base, const Employee* pilot)
167 {
168  bool found = false;
169 
170  AIR_ForeachFromBase(aircraft, base) {
171  if (AIR_GetPilot(aircraft) == pilot) {
172  found = true;
173  break;
174  }
175  }
176 
177  return found;
178 }
179 
186 void BDEF_AddBattery (basedefenceType_t basedefType, base_t* base)
187 {
188  switch (basedefType) {
189  case BASEDEF_MISSILE:
190  if (base->numBatteries >= MAX_BASE_SLOT) {
191  cgi->Com_Printf("BDEF_AddBattery: too many missile batteries in base\n");
192  return;
193  }
194  if (base->numBatteries)
195  base->batteries[base->numBatteries].autofire = base->batteries[0].autofire;
196  else if (base->numLasers)
197  base->batteries[base->numBatteries].autofire = base->lasers[0].autofire;
198  else
199  base->batteries[base->numBatteries].autofire = true;
200  base->numBatteries++;
201  break;
202  case BASEDEF_LASER:
203  if (base->numLasers >= MAX_BASE_SLOT) {
204  cgi->Com_Printf("BDEF_AddBattery: too many laser batteries in base\n");
205  return;
206  }
208  if (base->numBatteries)
209  base->lasers[base->numLasers].autofire = base->batteries[0].autofire;
210  else if (base->numLasers)
211  base->lasers[base->numLasers].autofire = base->lasers[0].autofire;
212  else
213  base->lasers[base->numLasers].autofire = true;
214  base->numLasers++;
215  break;
216  default:
217  cgi->Com_Printf("BDEF_AddBattery: unknown type of air defence system.\n");
218  }
219 }
220 
230 void BDEF_RemoveBattery (base_t* base, basedefenceType_t basedefType, int idx)
231 {
232  assert(base);
233 
234  /* Select the type of base defence system to destroy */
235  switch (basedefType) {
236  case BASEDEF_MISSILE: /* this is a missile battery */
237  /* we must have at least one missile battery to remove it */
238  assert(base->numBatteries > 0);
239  /* look for an unequipped battery */
240  if (idx < 0) {
241  for (int i = 0; i < base->numBatteries; i++) {
242  if (!base->batteries[i].slot.item) {
243  idx = i;
244  break;
245  }
246  }
247  }
248  /* if none found remove the last one */
249  if (idx < 0)
250  idx = base->numBatteries - 1;
251  REMOVE_ELEM(base->batteries, idx, base->numBatteries);
252  /* just for security */
253  AII_InitialiseSlot(&base->batteries[base->numBatteries].slot, nullptr, base, nullptr, AC_ITEM_BASE_MISSILE);
254  break;
255  case BASEDEF_LASER: /* this is a laser battery */
256  /* we must have at least one laser battery to remove it */
257  assert(base->numLasers > 0);
258  /* look for an unequipped battery */
259  if (idx < 0) {
260  for (int i = 0; i < base->numLasers; i++) {
261  if (!base->lasers[i].slot.item) {
262  idx = i;
263  break;
264  }
265  }
266  }
267  /* if none found remove the last one */
268  if (idx < 0)
269  idx = base->numLasers - 1;
270  REMOVE_ELEM(base->lasers, idx, base->numLasers);
271  /* just for security */
272  AII_InitialiseSlot(&base->lasers[base->numLasers].slot, nullptr, base, nullptr, AC_ITEM_BASE_LASER);
273  break;
274  default:
275  cgi->Com_Printf("BDEF_RemoveBattery_f: unknown type of air defence system.\n");
276  }
277 }
278 
284 {
285  for (int i = 0; i < MAX_BASE_SLOT; i++) {
286  baseWeapon_t* battery = &base->batteries[i];
287  baseWeapon_t* laser = &base->lasers[i];
288  AII_InitialiseSlot(&battery->slot, nullptr, base, nullptr, AC_ITEM_BASE_MISSILE);
289  AII_InitialiseSlot(&laser->slot, nullptr, base, nullptr, AC_ITEM_BASE_LASER);
290  battery->autofire = true;
291  battery->target = nullptr;
292  laser->autofire = true;
293  laser->target = nullptr;
294  }
295 }
296 
302 {
303  for (int i = 0; i < installation->installationTemplate->maxBatteries; i++) {
304  baseWeapon_t* battery = &installation->batteries[i];
305  AII_InitialiseSlot(&battery->slot, nullptr, nullptr, installation, AC_ITEM_BASE_MISSILE);
306  battery->target = nullptr;
307  battery->autofire = true;
308  }
309 }
310 
311 
320 static void AII_UpdateOneInstallationDelay (base_t* base, installation_t* installation, aircraft_t* aircraft, aircraftSlot_t* slot)
321 {
322  assert(base || installation);
323 
324  /* if the item is already installed, nothing to do */
325  if (slot->installationTime == 0)
326  return;
327  else if (slot->installationTime > 0) {
328  /* the item is being installed */
329  slot->installationTime--;
330  /* check if installation is over */
331  if (slot->installationTime <= 0) {
332  /* Update stats values */
333  if (aircraft) {
334  AII_UpdateAircraftStats(aircraft);
336  _("%s was successfully installed into aircraft %s at %s."),
337  _(slot->item->name), aircraft->name, aircraft->homebase->name);
338  } else if (installation) {
339  Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("%s was successfully installed at installation %s."),
340  _(slot->item->name), installation->name);
341  } else {
342  Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("%s was successfully installed at %s."),
343  _(slot->item->name), base->name);
344  }
346  }
347  } else if (slot->installationTime < 0) {
348  /* the item is being removed */
349  slot->installationTime++;
350  if (slot->installationTime >= 0) {
351 #ifdef DEBUG
352  if (aircraft && aircraft->homebase != base)
353  Sys_Error("AII_UpdateOneInstallationDelay: aircraft->homebase and base pointers are out of sync\n");
354 #endif
355  const objDef_t* olditem = slot->item;
356  AII_RemoveItemFromSlot(base, slot, false);
357  if (aircraft) {
358  AII_UpdateAircraftStats(aircraft);
359  /* Only stop time and post a notice, if no new item to install is assigned */
360  if (!slot->item) {
362  _("%s was successfully removed from aircraft %s at %s."),
363  _(olditem->name), aircraft->name, base->name);
365  } else {
367  _ ("%s was successfully removed, starting installation of %s into aircraft %s at %s"),
368  _(olditem->name), _(slot->item->name), aircraft->name, base->name);
370  }
371  } else if (!slot->item) {
372  if (installation) {
374  _("%s was successfully removed from installation %s."),
375  _(olditem->name), installation->name);
376  } else {
377  Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("%s was successfully removed from %s."),
378  _(olditem->name), base->name);
379  }
381  }
382  }
383  }
384 }
385 
393 {
394  base_t* base;
395  int k;
396 
397  INS_Foreach(installation) {
398  for (k = 0; k < installation->installationTemplate->maxBatteries; k++)
399  AII_UpdateOneInstallationDelay(nullptr, installation, nullptr, &installation->batteries[k].slot);
400  }
401 
402  base = nullptr;
403  while ((base = B_GetNext(base)) != nullptr) {
404  /* Update base */
405  for (k = 0; k < base->numBatteries; k++)
406  AII_UpdateOneInstallationDelay(base, nullptr, nullptr, &base->batteries[k].slot);
407  for (k = 0; k < base->numLasers; k++)
408  AII_UpdateOneInstallationDelay(base, nullptr, nullptr, &base->lasers[k].slot);
409  }
410 
411  /* Update each aircraft */
412  AIR_Foreach(aircraft) {
413  if (AIR_IsAircraftInBase(aircraft)) {
414  /* Update electronics delay */
415  for (k = 0; k < aircraft->maxElectronics; k++)
416  AII_UpdateOneInstallationDelay(aircraft->homebase, nullptr, aircraft, aircraft->electronics + k);
417  /* Update weapons delay */
418  for (k = 0; k < aircraft->maxWeapons; k++)
419  AII_UpdateOneInstallationDelay(aircraft->homebase, nullptr, aircraft, aircraft->weapons + k);
420 
421  /* Update shield delay */
422  AII_UpdateOneInstallationDelay(aircraft->homebase, nullptr, aircraft, &aircraft->shield);
423  }
424  }
425 }
426 
434 {
435  assert(slot);
436 
437  if (slot->aircraft && !AIR_IsUFO(slot->aircraft) && !AIR_IsAircraftInBase(slot->aircraft))
438  return;
439 
440  /* Get the weapon (either current weapon or weapon to install after this one is removed) */
441  const objDef_t* item = slot->nextItem ? slot->nextItem : slot->item;
442  /* no items assigned */
443  if (!item)
444  return;
445  /* item not a weapon */
446  if (item->craftitem.type > AC_ITEM_WEAPON)
447  return;
448  /* don't try to add ammo to a slot that already has ammo */
449  if (slot->nextItem ? slot->nextAmmo : slot->ammo)
450  return;
451  /* Try every ammo usable with this weapon until we find one we have in storage */
452  for (int k = 0; k < item->numAmmos; k++) {
453  const objDef_t* ammo = item->ammos[k];
454  if (!ammo)
455  continue;
456  const technology_t* ammoTech = RS_GetTechForItem(ammo);
457  if (!AIM_SelectableCraftItem(slot, ammoTech))
458  continue;
459  base_t* base;
460  if (ammo->isVirtual)
461  base = nullptr;
462  else if (slot->aircraft)
463  base = slot->aircraft->homebase;
464  else
465  base = slot->base;
466  AII_AddAmmoToSlot(base, ammoTech, slot);
467  break;
468  }
469 }
470 
482 void AII_RemoveItemFromSlot (base_t* base, aircraftSlot_t* slot, bool ammo)
483 {
484  assert(slot);
485 
486  if (ammo) {
487  /* only remove the ammo */
488  if (slot->ammo) {
489  /* Can only remove non-virtual ammo */
490  if (!slot->ammo->isVirtual) {
491  if (base)
492  B_AddToStorage(base, slot->ammo, 1);
493  slot->ammo = nullptr;
494  slot->ammoLeft = 0;
495  }
496  }
497  } else if (slot->item) {
498  /* remove ammo */
499  AII_RemoveItemFromSlot(base, slot, true);
500  if (!slot->item->isVirtual) {
501  if (base)
502  B_AddToStorage(base, slot->item, 1);
503  /* the removal is over */
504  if (slot->nextItem) {
505  /* there is anoter item to install after this one */
506  slot->item = slot->nextItem;
507  /* we already removed nextItem from storage when it has been added to slot: don't use B_AddToStorage */
508  slot->ammo = slot->nextAmmo;
509  if (slot->ammo)
510  slot->ammoLeft = slot->ammo->ammo;
512  slot->nextItem = nullptr;
513  slot->nextAmmo = nullptr;
514  } else {
515  slot->item = nullptr;
516  /* make sure nextAmmo is removed too
517  * virtual ammos cannot be removed without the weapon itself */
518  slot->ammo = nullptr;
519  slot->ammoLeft = 0;
520  slot->installationTime = 0;
521  }
522  }
523  }
524 }
525 
535 void AII_RemoveNextItemFromSlot (base_t* base, aircraftSlot_t* slot, bool ammo)
536 {
537  assert(slot);
538 
539  if (ammo) {
540  /* only remove the ammo */
541  if (slot->nextAmmo) {
542  if (!slot->nextAmmo->isVirtual) {
543  if (base)
544  B_AddToStorage(base, slot->nextAmmo, 1);
545  slot->nextAmmo = nullptr;
546  }
547  }
548  } else if (slot->nextItem) {
549  /* Remove nextItem */
550  if (base)
551  B_AddToStorage(base, slot->nextItem, 1);
552  slot->nextItem = nullptr;
553  /* also remove ammo if any */
554  if (slot->nextAmmo)
555  AII_RemoveNextItemFromSlot(base, slot, true);
556  /* make sure nextAmmo is removed too
557  * virtual ammos cannot be removed without the weapon itself */
558  slot->nextAmmo = nullptr;
559  }
560 }
561 
568 {
569  assert(slot);
570 
571  /* no weapon assigned - failure */
572  if (!slot->item)
573  return false;
574  /* no ammo assigned - try adding one */
575  if (!slot->ammo)
576  AII_AutoAddAmmo(slot);
577  /* still no ammo assigned - failure */
578  if (!slot->ammo)
579  return false;
580  /* no reload needed - success */
581  if (slot->ammoLeft >= slot->ammo->ammo)
582  return true;
583 
584  if (slot->aircraft) {
585  /* PHALANX aircraft and UFO crafts */
586  if (AIR_IsUFO(slot->aircraft)) {
587  /* UFO - can always be reloaded */
588  slot->ammoLeft = slot->ammo->ammo;
590  } else {
591  /* PHALANX aircraft */
592  /* not at home */
593  if (!AIR_IsAircraftInBase(slot->aircraft))
594  return false;
595  /* no more ammo available */
596  if (!B_BaseHasItem(slot->aircraft->homebase, slot->ammo)) {
597  slot->ammo = nullptr;
599  return false;
600  }
601 
602  B_AddToStorage(slot->aircraft->homebase, slot->ammo, -1);
603  slot->ammoLeft = slot->ammo->ammo;
606  }
607  } else if (slot->base) {
608  /* Base Defence weapons */
609  /* no more ammo available */
610  if (!B_BaseHasItem(slot->base, slot->ammo))
611  return false;
612 
613  B_AddToStorage(slot->base, slot->ammo, -1);
614  slot->ammoLeft = slot->ammo->ammo;
616  } else if (slot->installation) {
617  /* Installations (SAM-Sites) - can always be reloaded. */
618  slot->ammoLeft = slot->ammo->ammo;
620  } else {
621  cgi->Com_Error(ERR_DROP, "AII_ReloadWeapon: AircraftSlot not linked anywhere (aircraft/base/installation)!\n");
622  }
623  return true;
624 }
625 
631 {
632  assert(aircraft);
633  /* Reload all ammos of aircraft */
634  for (int i = 0; i < aircraft->maxWeapons; i++) {
635  AII_ReloadWeapon(&aircraft->weapons[i]);
636  }
637 }
638 
647 bool AII_AddAmmoToSlot (base_t* base, const technology_t* tech, aircraftSlot_t* slot)
648 {
649  if (slot == nullptr || slot->item == nullptr)
650  return false;
651 
652  assert(tech);
653 
654  const objDef_t* ammo = INVSH_GetItemByID(tech->provides);
655  if (!ammo) {
656  cgi->Com_Printf("AII_AddAmmoToSlot: Could not add item (%s) to slot\n", tech->provides);
657  return false;
658  }
659 
660  const objDef_t* item = (slot->nextItem) ? slot->nextItem : slot->item;
661 
662  /* Is the ammo is usable with the slot */
663  int k;
664  for (k = 0; k < item->numAmmos; k++) {
665  const objDef_t* usable = item->ammos[k];
666  if (usable && ammo->idx == usable->idx)
667  break;
668  }
669  if (k >= item->numAmmos)
670  return false;
671 
672  /* the base pointer can be null here - e.g. in case you are equipping a UFO
673  * and base ammo defence are not stored in storage */
674  if (base && ammo->craftitem.type <= AC_ITEM_AMMO) {
675  if (!B_BaseHasItem(base, ammo)) {
676  cgi->Com_Printf("AII_AddAmmoToSlot: No more ammo of this type to equip (%s)\n", ammo->id);
677  return false;
678  }
679  }
680 
681  /* remove any applied ammo in the current slot */
682  if (slot->nextItem) {
683  if (slot->nextAmmo)
684  AII_RemoveNextItemFromSlot(base, slot, true);
685  /* ammo couldn't be removed (maybe it's virtual) */
686  if (slot->nextAmmo)
687  return false;
688  slot->nextAmmo = ammo;
689  } else {
690  /* you shouldn't be able to have nextAmmo set if you don't have nextItem set */
691  assert(!slot->nextAmmo);
692  AII_RemoveItemFromSlot(base, slot, true);
693  /* ammo couldn't be removed (maybe it's virtual) */
694  if (slot->ammo)
695  return false;
696  slot->ammo = ammo;
697  }
698 
699  /* proceed only if we are changing ammo of current weapon */
700  if (slot->nextItem) {
701  /* the base pointer can be null here - e.g. in case you are equipping a UFO */
702  if (base)
703  B_AddToStorage(base, ammo, -1);
704  return true;
705  }
706  AII_ReloadWeapon(slot);
707 
708  return true;
709 }
710 
722 bool AII_AddItemToSlot (base_t* base, const technology_t* tech, aircraftSlot_t* slot, bool nextItem)
723 {
724  const objDef_t* item;
725 
726  assert(slot);
727  assert(tech);
728 
729  item = INVSH_GetItemByID(tech->provides);
730  if (!item) {
731  cgi->Com_Printf("AII_AddItemToSlot: Could not add item (%s) to slot\n", tech->provides);
732  return false;
733  }
734 
735 #ifdef DEBUG
736  /* Sanity check : the type of the item cannot be an ammo */
737  /* note that this should never be reached because a slot type should never be an ammo
738  * , so the test just before should be wrong */
739  if (item->craftitem.type >= AC_ITEM_AMMO) {
740  cgi->Com_Printf("AII_AddItemToSlot: Type of the item to install (%s) should be a weapon, a shield, or electronics (no ammo)\n", item->id);
741  return false;
742  }
743 #endif
744 
745  /* Sanity check : the type of the item should be the same than the slot type */
746  if (slot->type != item->craftitem.type) {
747  cgi->Com_Printf("AII_AddItemToSlot: Type of the item to install (%s -- %i) doesn't match type of the slot (%i)\n", item->id, item->craftitem.type, slot->type);
748  return false;
749  }
750 
751  /* the base pointer can be null here - e.g. in case you are equipping a UFO */
752  if (base && !B_BaseHasItem(base, item)) {
753  cgi->Com_Printf("AII_AddItemToSlot: No more item of this type to equip (%s)\n", item->id);
754  return false;
755  }
756 
757  if (slot->size >= AII_GetItemWeightBySize(item)) {
758  if (nextItem)
759  slot->nextItem = item;
760  else {
761  slot->item = item;
763  }
764  /* the base pointer can be null here - e.g. in case you are equipping a UFO
765  * Remove item even for nextItem, this way we are sure we won't use the same item
766  * for another aircraft. */
767  if (base)
768  B_AddToStorage(base, item, -1);
769  } else {
770  cgi->Com_Printf("AII_AddItemToSlot: Could not add item '%s' to slot %i (slot-size: %i - item-weight: %i)\n",
771  item->id, slot->idx, slot->size, item->size);
772  return false;
773  }
774 
775  return true;
776 }
777 
785 {
786  int i;
787  const objDef_t* item;
789  const technology_t* tech = RS_GetTechByID("rs_craft_weapon_sparrowhawk");
790 
791  if (!tech)
792  cgi->Com_Error(ERR_DROP, "Could not get tech rs_craft_weapon_sparrowhawk");
793 
794  assert(aircraft);
795  assert(aircraft->homebase);
796 
797  item = INVSH_GetItemByID(tech->provides);
798  if (!item)
799  return;
800 
801  for (i = 0; i < aircraft->maxWeapons; i++) {
802  aircraftSlot_t* slot = &aircraft->weapons[i];
803  if (slot->size < AII_GetItemWeightBySize(item))
804  continue;
805  if (!B_BaseHasItem(aircraft->homebase, item))
806  continue;
807  AII_AddItemToSlot(aircraft->homebase, tech, slot, false);
808  AII_AutoAddAmmo(slot);
809  slot->installationTime = 0;
810  }
811 
812  /* Fill slots too small for sparrowhawk with shiva */
813  tech = RS_GetTechByID("rs_craft_weapon_shiva");
814 
815  if (!tech)
816  cgi->Com_Error(ERR_DROP, "Could not get tech rs_craft_weapon_shiva");
817 
818  item = INVSH_GetItemByID(tech->provides);
819 
820  if (!item)
821  return;
822 
823  for (i = 0; i < aircraft->maxWeapons; i++) {
824  aircraftSlot_t* slot = &aircraft->weapons[i];
825  if (slot->size < AII_GetItemWeightBySize(item))
826  continue;
827  if (!B_BaseHasItem(aircraft->homebase, item))
828  continue;
829  if (slot->item)
830  continue;
831  AII_AddItemToSlot(aircraft->homebase, tech, slot, false);
832  AII_AutoAddAmmo(slot);
833  slot->installationTime = 0;
834  }
835 
836  AII_UpdateAircraftStats(aircraft);
837 }
838 
847 void AII_InitialiseSlot (aircraftSlot_t* slot, aircraft_t* aircraftTemplate, base_t* base, installation_t* installation, aircraftItemType_t type)
848 {
849  /* Only one of them is allowed. */
850  assert((!base && aircraftTemplate) || (base && !aircraftTemplate) || (installation && !aircraftTemplate));
851  /* Only one of them is allowed or neither. */
852  assert((!base && installation) || (base && !installation) || (!base && !installation));
853 
854  OBJZERO(*slot);
855  slot->aircraft = aircraftTemplate;
856  slot->base = base;
857  slot->installation = installation;
858  slot->item = nullptr;
859  slot->ammo = nullptr;
860  slot->nextAmmo = nullptr;
861  slot->size = ITEM_HEAVY;
862  slot->nextItem = nullptr;
863  slot->type = type;
866  slot->installationTime = 0;
867 }
868 
875 static bool AII_CheckUpdateAircraftStats (const aircraftSlot_t* slot, int stat)
876 {
877  assert(slot);
878 
879  /* there's no item */
880  if (!slot->item)
881  return false;
882 
883  /* you can not have advantages from items if it is being installed or removed, but only disavantages */
884  if (slot->installationTime != 0) {
885  const objDef_t* item = slot->item;
886  if (item->craftitem.stats[stat] > 1.0f) /* advantages for relative and absolute values */
887  return false;
888  }
889 
890  return true;
891 }
892 
901 {
902  switch (type) {
904  if (idx < 0) { /* returns the first free slot on negative */
905  int i;
906  for (i = 0; i < base->numBatteries; i++) {
907  aircraftSlot_t* slot = &base->batteries[i].slot;
908  if (!slot->item && !slot->nextItem)
909  return slot;
910  }
911  } else if (idx < base->numBatteries)
912  return &base->batteries[idx].slot;
913  break;
914  case AC_ITEM_BASE_LASER:
915  if (idx < 0) { /* returns the first free slot on negative */
916  int i;
917  for (i = 0; i < base->numLasers; i++) {
918  aircraftSlot_t* slot = &base->lasers[i].slot;
919  if (!slot->item && !slot->nextItem)
920  return slot;
921  }
922  } else if (idx < base->numLasers)
923  return &base->lasers[idx].slot;
924  break;
925  default:
926  break;
927  }
928  return nullptr;
929 }
930 
939 {
940  switch (type) {
942  if (idx < 0) { /* returns the first free slot on negative */
943  for (int i = 0; i < installation->numBatteries; i++) {
944  aircraftSlot_t* slot = &installation->batteries[i].slot;
945  if (!slot->item && !slot->nextItem)
946  return slot;
947  }
948  } else if (idx < installation->numBatteries)
949  return &installation->batteries[idx].slot;
950  break;
951  default:
952  break;
953  }
954  return nullptr;
955 }
956 
965 {
966  switch (type) {
967  case AC_ITEM_WEAPON:
968  if (idx < 0) { /* returns the first free slot on negative */
969  for (int i = 0; i < aircraft->maxWeapons; i++) {
970  aircraftSlot_t* slot = &aircraft->weapons[i];
971  if (!slot->item && !slot->nextItem)
972  return slot;
973  }
974  } else if (idx < aircraft->maxWeapons)
975  return &aircraft->weapons[idx];
976  break;
977  case AC_ITEM_SHIELD:
978  if (idx == 0 || ((idx < 0) && !aircraft->shield.item && !aircraft->shield.nextItem)) /* returns the first free slot on negative */
979  return &aircraft->shield;
980  break;
981  case AC_ITEM_ELECTRONICS:
982  if (idx < 0) { /* returns the first free slot on negative */
983  for (int i = 0; i < aircraft->maxElectronics; i++) {
984  aircraftSlot_t* slot = &aircraft->electronics[i];
985  if (!slot->item && !slot->nextItem)
986  return slot;
987  }
988  } else if (idx < aircraft->maxElectronics)
989  return &aircraft->electronics[idx];
990  break;
991  default:
992  break;
993  }
994  return nullptr;
995 }
996 
997 
1004 float AIR_GetMaxAircraftWeaponRange (const aircraftSlot_t* slot, int maxSlot)
1005 {
1006  float range = 0.0f;
1007 
1008  assert(slot);
1009 
1010  /* We choose the usable weapon with the biggest range */
1011  for (int i = 0; i < maxSlot; i++) {
1012  const aircraftSlot_t* weapon = slot + i;
1013  const objDef_t* ammo = weapon->ammo;
1014 
1015  if (!ammo)
1016  continue;
1017 
1018  /* make sure this item is useable */
1020  continue;
1021 
1022  /* select this weapon if this is the one with the longest range */
1023  if (ammo->craftitem.stats[AIR_STATS_WRANGE] > range) {
1024  range = ammo->craftitem.stats[AIR_STATS_WRANGE];
1025  }
1026  }
1027  return range;
1028 }
1029 
1036 {
1037  base_t* base = nullptr;
1038 
1039  while ((base = B_GetNext(base)) != nullptr) {
1040  AIR_ForeachFromBase(aircraft, base) {
1041  if (!AIR_IsAircraftInBase(aircraft))
1042  continue;
1043  const int REPAIR_PER_HOUR = std::max(1, int(round(aircraft->stats[AIR_STATS_DAMAGE] / 100)));
1044  cgi->Com_DPrintf(DEBUG_CLIENT, "Repair per hour: %s %d, %d / %d\n",
1045  aircraft->name, REPAIR_PER_HOUR, aircraft->damage, aircraft->stats[AIR_STATS_DAMAGE]);
1046  aircraft->damage = std::min(aircraft->damage + REPAIR_PER_HOUR, aircraft->stats[AIR_STATS_DAMAGE]);
1047  }
1048  }
1049 }
1050 
1057 {
1058  assert(aircraft);
1059 
1060  const aircraft_t* source = aircraft->tpl;
1061 
1062  for (int currentStat = 0; currentStat < AIR_STATS_MAX; currentStat++) {
1063  /* we scan all the stats except AIR_STATS_WRANGE (see below) */
1064  if (currentStat == AIR_STATS_WRANGE)
1065  continue;
1066 
1067  /* initialise value */
1068  aircraft->stats[currentStat] = source->stats[currentStat];
1069 
1070  /* modify by electronics (do nothing if the value of stat is 0) */
1071  for (int i = 0; i < aircraft->maxElectronics; i++) {
1072  const aircraftSlot_t* slot = &aircraft->electronics[i];
1073  const objDef_t* item;
1074  if (!AII_CheckUpdateAircraftStats(slot, currentStat))
1075  continue;
1076  item = slot->item;
1077  if (fabs(item->craftitem.stats[currentStat]) > 2.0f)
1078  aircraft->stats[currentStat] += (int) item->craftitem.stats[currentStat];
1079  else if (!EQUAL(item->craftitem.stats[currentStat], 0))
1080  aircraft->stats[currentStat] *= item->craftitem.stats[currentStat];
1081  }
1082 
1083  /* modify by weapons (do nothing if the value of stat is 0)
1084  * note that stats are not modified by ammos */
1085  for (int i = 0; i < aircraft->maxWeapons; i++) {
1086  const aircraftSlot_t* slot = &aircraft->weapons[i];
1087  const objDef_t* item;
1088  if (!AII_CheckUpdateAircraftStats(slot, currentStat))
1089  continue;
1090  item = slot->item;
1091  if (fabs(item->craftitem.stats[currentStat]) > 2.0f)
1092  aircraft->stats[currentStat] += item->craftitem.stats[currentStat];
1093  else if (!EQUAL(item->craftitem.stats[currentStat], 0))
1094  aircraft->stats[currentStat] *= item->craftitem.stats[currentStat];
1095  }
1096 
1097  /* modify by shield (do nothing if the value of stat is 0) */
1098  if (AII_CheckUpdateAircraftStats(&aircraft->shield, currentStat)) {
1099  const objDef_t* item = aircraft->shield.item;
1100  if (fabs(item->craftitem.stats[currentStat]) > 2.0f)
1101  aircraft->stats[currentStat] += item->craftitem.stats[currentStat];
1102  else if (!EQUAL(item->craftitem.stats[currentStat], 0))
1103  aircraft->stats[currentStat] *= item->craftitem.stats[currentStat];
1104  }
1105  }
1106 
1107  /* now we update AIR_STATS_WRANGE (this one is the biggest range of every ammo) */
1108  aircraft->stats[AIR_STATS_WRANGE] = 1000.0f * AIR_GetMaxAircraftWeaponRange(aircraft->weapons, aircraft->maxWeapons);
1109 
1110  /* check that aircraft hasn't too much fuel (caused by removal of fuel pod) */
1111  if (aircraft->fuel > aircraft->stats[AIR_STATS_FUELSIZE])
1112  aircraft->fuel = aircraft->stats[AIR_STATS_FUELSIZE];
1113 
1114  /* check that aircraft hasn't too much HP (caused by removal of armour) */
1115  if (aircraft->damage > aircraft->stats[AIR_STATS_DAMAGE])
1116  aircraft->damage = aircraft->stats[AIR_STATS_DAMAGE];
1117 
1118  /* check that speed of the aircraft is positive */
1119  if (aircraft->stats[AIR_STATS_SPEED] < 1)
1120  aircraft->stats[AIR_STATS_SPEED] = 1;
1121 
1122  /* Update aircraft state if needed */
1123  if (aircraft->status == AIR_HOME && aircraft->fuel < aircraft->stats[AIR_STATS_FUELSIZE])
1124  aircraft->status = AIR_REFUEL;
1125 }
1126 
1134 static bool AII_WeaponsCanShoot (const baseWeapon_t* weapons, int numWeapons)
1135 {
1136  for (int i = 0; i < numWeapons; i++) {
1137  if (AIRFIGHT_CheckWeapon(&weapons[i].slot, 0) != AIRFIGHT_WEAPON_CAN_NEVER_SHOOT)
1138  return true;
1139  }
1140 
1141  return false;
1142 }
1143 
1150 int AII_BaseCanShoot (const base_t* base)
1151 {
1152  assert(base);
1153 
1154  /* If we can shoot with missile defences */
1156  && AII_WeaponsCanShoot(base->batteries, base->numBatteries))
1157  return true;
1158 
1159  /* If we can shoot with beam defences */
1161  && AII_WeaponsCanShoot(base->lasers, base->numLasers))
1162  return true;
1163 
1164  return false;
1165 }
1166 
1173 bool AII_InstallationCanShoot (const installation_t* installation)
1174 {
1175  assert(installation);
1176 
1177  if (installation->installationStatus == INSTALLATION_WORKING
1178  && installation->installationTemplate->maxBatteries > 0) {
1179  /* installation is working and has battery */
1180  return AII_WeaponsCanShoot(installation->batteries, installation->installationTemplate->maxBatteries);
1181  }
1182 
1183  return false;
1184 }
1185 
1191 static void BDEF_AutoTarget (baseWeapon_t* weapons, int maxWeapons)
1192 {
1193  if (maxWeapons <= 0)
1194  return;
1195 
1196  const installation_t* inst;
1197  const base_t* base;
1198  const aircraftSlot_t* slot = &weapons[0].slot;
1199  /* Check if it's a Base or an Installation */
1200  if (slot->installation) {
1201  inst = slot->installation;
1202  base = nullptr;
1203  } else if (slot->base) {
1204  base = slot->base;
1205  inst = nullptr;
1206  } else
1207  cgi->Com_Error(ERR_DROP, "BDEF_AutoSelectTarget: slot doesn't belong to any base or installation");
1208 
1209  /* Get closest UFO(s) */
1210  aircraft_t* closestCraft = nullptr;
1211  float minCraftDistance = -1;
1212  aircraft_t* closestAttacker = nullptr;
1213  float minAttackerDistance = -1;
1214  aircraft_t* ufo = nullptr;
1215  while ((ufo = UFO_GetNextOnGeoscape(ufo)) != nullptr) {
1216  const float distance = GetDistanceOnGlobe(inst ? inst->pos : base->pos, ufo->pos);
1217  if (minCraftDistance < 0 || minCraftDistance > distance) {
1218  minCraftDistance = distance;
1219  closestCraft = ufo;
1220  }
1221  if ((minAttackerDistance < 0 || minAttackerDistance > distance) && ufo->mission
1222  && ((base && ufo->mission->category == INTERESTCATEGORY_BASE_ATTACK && ufo->mission->data.base == base)
1223  || (inst && ufo->mission->category == INTERESTCATEGORY_INTERCEPT && ufo->mission->data.installation == inst))) {
1224  minAttackerDistance = distance;
1225  closestAttacker = ufo;
1226  }
1227  }
1228 
1229  /* Loop weaponslots */
1230  for (int i = 0; i < maxWeapons; i++) {
1231  baseWeapon_t* weapon = &weapons[i];
1232  slot = &weapon->slot;
1233  /* skip if autofire is disabled */
1234  if (!weapon->autofire)
1235  continue;
1236  /* skip if no weapon or ammo assigned */
1237  if (!slot->item || !slot->ammo)
1238  continue;
1239  /* skip if weapon installation not yet finished */
1240  if (slot->installationTime > 0)
1241  continue;
1242  /* skip if no more ammo left */
1244  if (slot->ammoLeft <= 0)
1245  continue;
1246 
1247  if (closestAttacker) {
1248  const int test = AIRFIGHT_CheckWeapon(slot, minAttackerDistance);
1251  && (minAttackerDistance <= slot->ammo->craftitem.stats[AIR_STATS_WRANGE]))
1252  weapon->target = closestAttacker;
1253  } else if (closestCraft) {
1254  const int test = AIRFIGHT_CheckWeapon(slot, minCraftDistance);
1257  && (minCraftDistance <= slot->ammo->craftitem.stats[AIR_STATS_WRANGE]))
1258  weapon->target = closestCraft;
1259  }
1260  }
1261 }
1262 
1267 {
1268  base_t* base;
1269 
1270  base = nullptr;
1271  while ((base = B_GetNext(base)) != nullptr) {
1272  BDEF_AutoTarget(base->batteries, base->numBatteries);
1273  BDEF_AutoTarget(base->lasers, base->numLasers);
1274  }
1275 
1276  INS_Foreach(inst)
1277  BDEF_AutoTarget(inst->batteries, inst->numBatteries);
1278 }
1279 
1285 const char* AII_WeightToName (itemWeight_t weight)
1286 {
1287  switch (weight) {
1288  case ITEM_LIGHT:
1289  return _("Light weight");
1290  break;
1291  case ITEM_MEDIUM:
1292  return _("Medium weight");
1293  break;
1294  case ITEM_HEAVY:
1295  return _("Heavy weight");
1296  break;
1297  default:
1298  return _("Unknown weight");
1299  break;
1300  }
1301 }
1302 
1309 void AII_SaveOneSlotXML (xmlNode_t* p, const aircraftSlot_t* slot, bool weapon)
1310 {
1311  cgi->XML_AddStringValue(p, SAVE_SLOT_ITEMID, slot->item ? slot->item->id : "");
1312  cgi->XML_AddStringValue(p, SAVE_SLOT_NEXTITEMID, slot->nextItem ? slot->nextItem->id : "");
1313  cgi->XML_AddIntValue(p, SAVE_SLOT_INSTALLATIONTIME, slot->installationTime);
1314 
1315  /* everything below is only for weapon */
1316  if (!weapon)
1317  return;
1318 
1319  cgi->XML_AddIntValue(p, SAVE_SLOT_AMMOLEFT, slot->ammoLeft);
1320  cgi->XML_AddStringValue(p, SAVE_SLOT_AMMOID, slot->ammo ? slot->ammo->id : "");
1321  cgi->XML_AddStringValue(p, SAVE_SLOT_NEXTAMMOID, slot->nextAmmo ? slot->nextAmmo->id : "");
1322  cgi->XML_AddIntValue(p, SAVE_SLOT_DELAYNEXTSHOT, slot->delayNextShot);
1323 }
1324 
1333 void AII_LoadOneSlotXML (xmlNode_t* node, aircraftSlot_t* slot, bool weapon)
1334 {
1335  const char* name;
1337  if (name[0] != '\0') {
1338  const technology_t* tech = RS_GetTechByProvided(name);
1339  /* base is nullptr here to not check against the storage amounts - they
1340  * are already loaded in the campaign load function and set to the value
1341  * after the craftitem was already removed from the initial game - thus
1342  * there might not be any of these items in the storage at this point.
1343  * Furthermore, they have already be taken from storage during game. */
1344  if (tech)
1345  AII_AddItemToSlot(nullptr, tech, slot, false);
1346  }
1347 
1348  /* item to install after current one is removed */
1350  if (name && name[0] != '\0') {
1351  const technology_t* tech = RS_GetTechByProvided(name);
1352  if (tech)
1353  AII_AddItemToSlot(nullptr, tech, slot, true);
1354  }
1355 
1356  slot->installationTime = cgi->XML_GetInt(node, SAVE_SLOT_INSTALLATIONTIME, 0);
1357 
1358  /* everything below is weapon specific */
1359  if (!weapon)
1360  return;
1361 
1362  /* current ammo */
1363  /* load ammoLeft before adding ammo to avoid unnecessary auto-reloading */
1364  slot->ammoLeft = cgi->XML_GetInt(node, SAVE_SLOT_AMMOLEFT, 0);
1366  if (name && name[0] != '\0') {
1367  const technology_t* tech = RS_GetTechByProvided(name);
1368  /* next Item must not be loaded yet in order to install ammo properly */
1369  if (tech)
1370  AII_AddAmmoToSlot(nullptr, tech, slot);
1371  }
1372  /* ammo to install after current one is removed */
1374  if (name && name[0] != '\0') {
1375  const technology_t* tech = RS_GetTechByProvided(name);
1376  if (tech)
1377  AII_AddAmmoToSlot(nullptr, tech, slot);
1378  }
1379  slot->delayNextShot = cgi->XML_GetInt(node, SAVE_SLOT_DELAYNEXTSHOT, 0);
1380 }
#define UFO_RELOAD_DELAY_MULTIPLIER
bool AIM_PilotAssignedAircraft(const base_t *base, const Employee *pilot)
Checks to see if the pilot is in any aircraft at this base.
static bool AII_WeaponsCanShoot(const baseWeapon_t *weapons, int numWeapons)
Check if base or installation weapon can shoot.
struct base_s * homebase
Definition: cp_aircraft.h:150
struct aircraft_s * aircraft
Definition: cp_aircraft.h:82
aircraftStatus_t status
Definition: cp_aircraft.h:126
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
#define AIRFIGHT_WEAPON_CAN_NEVER_SHOOT
Definition: cp_airfight.h:38
bool AIR_IsAircraftInBase(const aircraft_t *aircraft)
Checks whether given aircraft is in its homebase.
csi_t * csi
Definition: cgame.h:100
uiMessageListNodeMessage_t * MSO_CheckAddNewMessage(const notify_t messagecategory, const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup)
Adds a new message to message stack. It uses message settings to verify whether sound should be playe...
void BDEF_AutoSelectTarget(void)
Chooses target for all base defences and sam sites.
aircraftSlot_t * BDEF_GetInstallationSlotByIDX(installation_t *installation, aircraftItemType_t type, int idx)
returns the aircraftSlot of an installaion at an index or the first free slot
void BDEF_InitialiseInstallationSlots(installation_t *installation)
Initialise all values of installation slot defence.
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
const objDef_t * INVSH_GetItemByID(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn&#39;t found.
Definition: inv_shared.cpp:282
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:478
aircraftSlot_t * AII_GetAircraftSlotByIDX(aircraft_t *aircraft, aircraftItemType_t type, int idx)
returns the aircraftSlot of an aircraft at an index or the first free slot
int AIRFIGHT_CheckWeapon(const aircraftSlot_t *slot, float distance)
Check if the selected weapon can shoot.
A base with all it&#39;s data.
Definition: cp_base.h:84
#define SAVE_SLOT_AMMOID
void AII_UpdateAircraftStats(aircraft_t *aircraft)
Update the value of stats array of an aircraft.
installationStatus_t installationStatus
#define _(String)
Definition: cl_shared.h:44
int maxWeapons
Definition: cp_aircraft.h:145
void AIM_AutoEquipAircraft(aircraft_t *aircraft)
Auto Add weapon and ammo to an aircraft.
XML tag constants for savegame.
baseWeapon_t lasers[MAX_BASE_SLOT]
Definition: cp_base.h:119
#define EQUAL(a, b)
Definition: vector.h:37
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
int B_AddToStorage(base_t *base, const objDef_t *obj, int amount)
Add/remove items to/from the storage.
Definition: cp_base.cpp:2576
struct base_s * base
Definition: cp_aircraft.h:80
bool AII_AddAmmoToSlot(base_t *base, const technology_t *tech, aircraftSlot_t *slot)
Add an ammo to an aircraft weapon slot.
static void BDEF_AutoTarget(baseWeapon_t *weapons, int maxWeapons)
Chooses a target for surface to air defences automatically.
bool AII_InstallationCanShoot(const installation_t *installation)
Check if the installation has a weapon and ammo.
char name[MAX_VAR]
Definition: cp_base.h:86
#define MAX_BASE_SLOT
Definition: cp_base.h:35
void BDEF_RemoveBattery(base_t *base, basedefenceType_t basedefType, int idx)
Remove a base defence sytem from base.
int installationTime
Definition: cp_aircraft.h:90
aircraftSlot_t slot
Definition: cp_base.h:78
itemWeight_t size
Definition: cp_aircraft.h:87
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void AII_RepairAircraft(void)
Repair aircraft.
char name[MAX_VAR]
Definition: cp_aircraft.h:121
aircraft_t * UFO_GetNextOnGeoscape(aircraft_t *lastUFO)
Definition: cp_ufo.cpp:66
aircraftItemType_t type
Definition: cp_aircraft.h:83
A installation with all it&#39;s data.
itemWeight_t AII_GetItemWeightBySize(const objDef_t *od)
Returns craftitem weight based on size.
float AIR_GetMaxAircraftWeaponRange(const aircraftSlot_t *slot, int maxSlot)
Get the maximum weapon range of aircraft.
#define SAVE_SLOT_NEXTAMMOID
int maxElectronics
Definition: cp_aircraft.h:148
#define INSTALLATION_RELOAD_DELAY_MULTIPLIER
#define INS_Foreach(var)
#define xmlNode_t
Definition: xml.h:24
float weaponDelay
Definition: inv_shared.h:251
float stats[AIR_STATS_MAX]
Definition: inv_shared.h:248
#define AIRCRAFT_RELOAD_DELAY_MULTIPLIER
#define REMOVE_ELEM(array, index, n)
Definition: common.h:384
void AII_ReloadAircraftWeapons(aircraft_t *aircraft)
Reload the weapons of an aircraft.
#define AIRFIGHT_WEAPON_CAN_NOT_SHOOT_AT_THE_MOMENT
Definition: cp_airfight.h:37
int numLasers
Definition: cp_base.h:120
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition: inv_shared.h:307
#define ERR_DROP
Definition: common.h:211
#define DEBUG_CLIENT
Definition: defines.h:59
slot of aircraft
Definition: cp_aircraft.h:78
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
Definition: cp_aircraft.h:144
#define OBJZERO(obj)
Definition: shared.h:178
aircraftSlot_t * BDEF_GetBaseSlotByIDX(base_t *base, aircraftItemType_t type, int idx)
returns the aircraftSlot of a base at an index or the first free slot
Campaign missions headers.
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition: cp_base.cpp:286
const char *IMPORT * XML_GetString(xmlNode_t *parent, const char *name)
const cgame_import_t * cgi
static void AII_UpdateOneInstallationDelay(base_t *base, installation_t *installation, aircraft_t *aircraft, aircraftSlot_t *slot)
Update the installation delay of one slot.
const objDef_t * nextAmmo
Definition: cp_aircraft.h:94
struct aircraft_s * tpl
Definition: cp_aircraft.h:119
vec3_t pos
Definition: cp_aircraft.h:132
Employee * AIR_GetPilot(const aircraft_t *aircraft)
Get pilot of an aircraft.
int numODs
Definition: q_shared.h:518
#define SAVE_SLOT_DELAYNEXTSHOT
const objDef_t * ammo
Definition: cp_aircraft.h:86
bool autofire
Definition: cp_base.h:80
struct installation_s * installation
Definition: cp_aircraft.h:81
craftItem craftitem
Definition: inv_shared.h:331
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:311
void BDEF_AddBattery(basedefenceType_t basedefType, base_t *base)
Adds a defence system to base.
baseWeapon_t batteries[MAX_INSTALLATION_BATTERIES]
int stats[AIR_STATS_MAX]
Definition: cp_aircraft.h:160
char cp_messageBuffer[MAX_MESSAGE_TEXT]
Definition: cp_messages.cpp:33
#define BASE_RELOAD_DELAY_MULTIPLIER
bool AII_AddItemToSlot(base_t *base, const technology_t *tech, aircraftSlot_t *slot, bool nextItem)
Add an item to an aircraft slot.
int ammo
Definition: inv_shared.h:293
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
Definition: cp_aircraft.h:202
char * provides
Definition: cp_research.h:156
baseWeapon_t batteries[MAX_BASE_SLOT]
Definition: cp_base.h:116
An aircraft with all it&#39;s data.
Definition: cp_aircraft.h:115
#define SAVE_SLOT_NEXTITEMID
bool isVirtual
Definition: inv_shared.h:284
const char * id
Definition: inv_shared.h:268
struct mission_s * mission
Definition: cp_aircraft.h:153
char name[MAX_VAR]
QGL_EXTERN GLint i
Definition: r_gl.h:113
void AII_InitialiseSlot(aircraftSlot_t *slot, aircraft_t *aircraftTemplate, base_t *base, installation_t *installation, aircraftItemType_t type)
Initialise values of one slot of an aircraft or basedefence common to all types of items...
void AII_LoadOneSlotXML(xmlNode_t *node, aircraftSlot_t *slot, bool weapon)
Loads one slot (base, installation or aircraft)
#define SAVE_SLOT_ITEMID
aircraftSlot_t shield
Definition: cp_aircraft.h:146
#define AIR_IsUFO(aircraft)
Definition: cp_aircraft.h:206
#define MAX_TECHNOLOGIES
Definition: cp_research.h:31
Header for slot management related stuff.
bool AIM_SelectableCraftItem(const aircraftSlot_t *slot, const technology_t *tech)
Check if an aircraft item should or should not be displayed in airequip menu.
This is the technology parsed from research.ufo.
Definition: cp_research.h:139
aircraftItemType_t
All different types of craft items.
Definition: inv_shared.h:197
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
bool B_BaseHasItem(const base_t *base, const objDef_t *item)
Check if an item is available on a base.
Definition: cp_base.cpp:2119
void AII_AutoAddAmmo(aircraftSlot_t *slot)
Auto add ammo corresponding to weapon, if there is enough in storage.
const char * name
Definition: inv_shared.h:267
const char * AII_WeightToName(itemWeight_t weight)
Translate a weight int to a translated string.
int installationTime
Definition: inv_shared.h:252
basedefenceType_t
The different possible types of base defence systems.
aircraft_t * target
Definition: cp_base.h:79
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
Header file for single player campaign control.
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
void AII_UpdateInstallationDelay(void)
Update the installation delay of all slots of a given aircraft.
aircraftItemType_t type
Definition: inv_shared.h:247
#define SAVE_SLOT_AMMOLEFT
static bool AII_CheckUpdateAircraftStats(const aircraftSlot_t *slot, int stat)
Check if item in given slot should change one aircraft stat.
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
int AII_BaseCanShoot(const base_t *base)
Check if the base has weapon and ammo.
aircraftSlot_t electronics[MAX_AIRCRAFTSLOT]
Definition: cp_aircraft.h:147
void BDEF_InitialiseBaseSlots(base_t *base)
Initialise all values of base slot defence.
#define lengthof(x)
Definition: shared.h:105
technology_t ** AII_GetCraftitemTechsByType(aircraftItemType_t type)
Returns a list of craftitem technologies for the given type.
const objDef_t * item
Definition: cp_aircraft.h:85
void AII_RemoveNextItemFromSlot(base_t *base, aircraftSlot_t *slot, bool ammo)
Cancel replacing item, move nextItem (or optionally its ammo only) back to the base storage...
#define AIR_Foreach(var)
iterates trough all aircraft
Definition: cp_aircraft.h:193
technology_t * RS_GetTechForItem(const objDef_t *item)
Returns technology entry for an item.
vec3_t pos
Definition: cp_base.h:91
int size
Definition: inv_shared.h:334
void AII_RemoveItemFromSlot(base_t *base, aircraftSlot_t *slot, bool ammo)
Remove the item from the slot (or optionally its ammo only) and put it the base storage.
int numBatteries
Definition: cp_base.h:117
const installationTemplate_t * installationTemplate
void AII_SaveOneSlotXML(xmlNode_t *p, const aircraftSlot_t *slot, bool weapon)
Save callback for savegames in XML Format.
int numAmmos
Definition: inv_shared.h:308
#define SAVE_SLOT_INSTALLATIONTIME
const objDef_t * nextItem
Definition: cp_aircraft.h:92
bool AII_ReloadWeapon(aircraftSlot_t *slot)
Reloads an aircraft/defence-system weapon.
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition: mathlib.cpp:171
itemWeight_t
different weight for aircraft items
Definition: cp_aircraft.h:48