UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_mapfightequip.cpp
Go to the documentation of this file.
1
7
8/*
9Copyright (C) 2002-2025 UFO: Alien Invasion.
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, 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"
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
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
166bool 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
186void 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
230void 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
320static 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
482void 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
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
647bool 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
722bool 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
847void 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
875static 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;
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;
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
1004float 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
1134static 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
1150int AII_BaseCanShoot (const base_t* base)
1151{
1152 assert(base);
1153
1154 /* If we can shoot with missile defences */
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
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
1191static 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) {
1273 BDEF_AutoTarget(base->lasers, base->numLasers);
1274 }
1275
1276 INS_Foreach(inst)
1277 BDEF_AutoTarget(inst->batteries, inst->numBatteries);
1278}
1279
1285const 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
1309void 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
1333void AII_LoadOneSlotXML (xmlNode_t* node, aircraftSlot_t* slot, bool weapon)
1334{
1335 const char* name;
1336 name = cgi->XML_GetString(node, SAVE_SLOT_ITEMID);
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 */
1349 name = cgi->XML_GetString(node, SAVE_SLOT_NEXTITEMID);
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);
1365 name = cgi->XML_GetString(node, SAVE_SLOT_AMMOID);
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 */
1373 name = cgi->XML_GetString(node, SAVE_SLOT_NEXTAMMOID);
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}
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
#define REMOVE_ELEM(array, index, n)
Definition common.h:385
#define ERR_DROP
Definition common.h:211
Employee * AIR_GetPilot(const aircraft_t *aircraft)
Get pilot of an aircraft.
bool AIR_IsAircraftInBase(const aircraft_t *aircraft)
Checks whether given aircraft is in its homebase.
itemWeight_t
different weight for aircraft items
Definition cp_aircraft.h:48
@ ITEM_HEAVY
Definition cp_aircraft.h:51
@ ITEM_MEDIUM
Definition cp_aircraft.h:50
@ ITEM_LIGHT
Definition cp_aircraft.h:49
#define AIR_Foreach(var)
iterates trough all aircraft
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
@ AIR_HOME
@ AIR_REFUEL
#define AIR_IsUFO(aircraft)
int AIRFIGHT_CheckWeapon(const aircraftSlot_t *slot, float distance)
Check if the selected weapon can shoot.
#define AIRFIGHT_WEAPON_CAN_NOT_SHOOT_AT_THE_MOMENT
Definition cp_airfight.h:37
#define AIRFIGHT_WEAPON_CAN_NEVER_SHOOT
Definition cp_airfight.h:38
@ INTERESTCATEGORY_BASE_ATTACK
@ INTERESTCATEGORY_INTERCEPT
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition cp_base.cpp:286
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
int B_AddToStorage(base_t *base, const objDef_t *obj, int amount)
Add/remove items to/from the storage.
Definition cp_base.cpp:2576
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition cp_base.cpp:478
#define MAX_BASE_SLOT
Definition cp_base.h:35
@ B_DEFENCE_LASER
Definition cp_building.h:66
@ B_DEFENCE_MISSILE
Definition cp_building.h:65
Header file for single player campaign control.
const cgame_import_t * cgi
#define INS_Foreach(var)
@ INSTALLATION_WORKING
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
void BDEF_AddBattery(basedefenceType_t basedefType, base_t *base)
Adds a defence system to base.
float AIR_GetMaxAircraftWeaponRange(const aircraftSlot_t *slot, int maxSlot)
Get the maximum weapon range of aircraft.
bool AII_ReloadWeapon(aircraftSlot_t *slot)
Reloads an aircraft/defence-system weapon.
void AII_RepairAircraft(void)
Repair aircraft.
void BDEF_InitialiseInstallationSlots(installation_t *installation)
Initialise all values of installation slot defence.
#define INSTALLATION_RELOAD_DELAY_MULTIPLIER
void BDEF_RemoveBattery(base_t *base, basedefenceType_t basedefType, int idx)
Remove a base defence sytem from base.
static bool AII_CheckUpdateAircraftStats(const aircraftSlot_t *slot, int stat)
Check if item in given slot should change one aircraft stat.
static void AII_UpdateOneInstallationDelay(base_t *base, installation_t *installation, aircraft_t *aircraft, aircraftSlot_t *slot)
Update the installation delay of one slot.
void AIM_AutoEquipAircraft(aircraft_t *aircraft)
Auto Add weapon and ammo to an aircraft.
void AII_LoadOneSlotXML(xmlNode_t *node, aircraftSlot_t *slot, bool weapon)
Loads one slot (base, installation or aircraft).
void AII_UpdateInstallationDelay(void)
Update the installation delay of all slots of a given aircraft.
#define BASE_RELOAD_DELAY_MULTIPLIER
itemWeight_t AII_GetItemWeightBySize(const objDef_t *od)
Returns craftitem weight based on size.
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
static bool AII_WeaponsCanShoot(const baseWeapon_t *weapons, int numWeapons)
Check if base or installation weapon can shoot.
#define UFO_RELOAD_DELAY_MULTIPLIER
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.
void AII_AutoAddAmmo(aircraftSlot_t *slot)
Auto add ammo corresponding to weapon, if there is enough in storage.
#define AIRCRAFT_RELOAD_DELAY_MULTIPLIER
const char * AII_WeightToName(itemWeight_t weight)
Translate a weight int to a translated string.
void AII_ReloadAircraftWeapons(aircraft_t *aircraft)
Reload the weapons of an aircraft.
void AII_UpdateAircraftStats(aircraft_t *aircraft)
Update the value of stats array of an aircraft.
technology_t ** AII_GetCraftitemTechsByType(aircraftItemType_t type)
Returns a list of craftitem technologies for the given type.
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
bool AII_AddItemToSlot(base_t *base, const technology_t *tech, aircraftSlot_t *slot, bool nextItem)
Add an item to an aircraft slot.
bool AII_AddAmmoToSlot(base_t *base, const technology_t *tech, aircraftSlot_t *slot)
Add an ammo to an aircraft weapon slot.
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.
void BDEF_AutoSelectTarget(void)
Chooses target for all base defences and sam sites.
void BDEF_InitialiseBaseSlots(base_t *base)
Initialise all values of base slot defence.
int AII_BaseCanShoot(const base_t *base)
Check if the base has weapon and ammo.
bool AII_InstallationCanShoot(const installation_t *installation)
Check if the installation has a weapon and ammo.
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.
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.
bool AIM_PilotAssignedAircraft(const base_t *base, const Employee *pilot)
Checks to see if the pilot is in any aircraft at this base.
void AII_SaveOneSlotXML(xmlNode_t *p, const aircraftSlot_t *slot, bool weapon)
Save callback for savegames in XML Format.
static void BDEF_AutoTarget(baseWeapon_t *weapons, int maxWeapons)
Chooses a target for surface to air defences automatically.
Header for slot management related stuff.
basedefenceType_t
The different possible types of base defence systems.
@ BASEDEF_MISSILE
@ BASEDEF_LASER
@ AMMO_STATUS_NOT_SET
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...
@ NT_INSTALLATION_INSTALLED
@ NT_INSTALLATION_REPLACE
@ NT_INSTALLATION_REMOVED
char cp_messageBuffer[MAX_MESSAGE_TEXT]
Campaign missions headers.
technology_t * RS_GetTechForItem(const objDef_t *item)
Returns technology entry for an item.
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
#define MAX_TECHNOLOGIES
Definition cp_research.h:31
aircraft_t * UFO_GetNextOnGeoscape(aircraft_t *lastUFO)
Definition cp_ufo.cpp:66
#define DEBUG_CLIENT
Definition defines.h:59
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
const objDef_t * INVSH_GetItemByID(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn't found.
@ AIR_STATS_MAX
Definition inv_shared.h:237
@ AIR_STATS_FUELSIZE
Definition inv_shared.h:232
@ AIR_STATS_WRANGE
Definition inv_shared.h:233
@ AIR_STATS_SPEED
Definition inv_shared.h:226
@ AIR_STATS_DAMAGE
Definition inv_shared.h:230
aircraftItemType_t
All different types of craft items.
Definition inv_shared.h:197
@ AC_ITEM_WEAPON
Definition inv_shared.h:201
@ AC_ITEM_AMMO
Definition inv_shared.h:211
@ AC_ITEM_BASE_LASER
Definition inv_shared.h:200
@ AC_ITEM_ELECTRONICS
Definition inv_shared.h:205
@ AC_ITEM_SHIELD
Definition inv_shared.h:204
@ AC_ITEM_BASE_MISSILE
Definition inv_shared.h:199
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition mathlib.cpp:171
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
XML tag constants for savegame.
#define SAVE_SLOT_AMMOID
#define SAVE_SLOT_ITEMID
#define SAVE_SLOT_INSTALLATIONTIME
#define SAVE_SLOT_NEXTITEMID
#define SAVE_SLOT_DELAYNEXTSHOT
#define SAVE_SLOT_NEXTAMMOID
#define SAVE_SLOT_AMMOLEFT
#define OBJZERO(obj)
Definition shared.h:178
#define lengthof(x)
Definition shared.h:105
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
An aircraft with all it's data.
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
int maxElectronics
struct base_s * homebase
aircraftStatus_t status
int stats[AIR_STATS_MAX]
aircraftSlot_t shield
struct mission_s * mission
struct aircraft_s * tpl
char name[MAX_VAR]
aircraftSlot_t electronics[MAX_AIRCRAFTSLOT]
slot of aircraft
Definition cp_aircraft.h:78
const objDef_t * item
Definition cp_aircraft.h:85
const objDef_t * nextAmmo
Definition cp_aircraft.h:94
const objDef_t * ammo
Definition cp_aircraft.h:86
struct installation_s * installation
Definition cp_aircraft.h:81
struct aircraft_s * aircraft
Definition cp_aircraft.h:82
struct base_s * base
Definition cp_aircraft.h:80
itemWeight_t size
Definition cp_aircraft.h:87
aircraftItemType_t type
Definition cp_aircraft.h:83
const objDef_t * nextItem
Definition cp_aircraft.h:92
A base with all it's data.
Definition cp_base.h:84
int numLasers
Definition cp_base.h:120
baseWeapon_t batteries[MAX_BASE_SLOT]
Definition cp_base.h:116
baseWeapon_t lasers[MAX_BASE_SLOT]
Definition cp_base.h:119
char name[MAX_VAR]
Definition cp_base.h:86
vec3_t pos
Definition cp_base.h:91
int numBatteries
Definition cp_base.h:117
aircraftSlot_t slot
Definition cp_base.h:78
aircraft_t * target
Definition cp_base.h:79
bool autofire
Definition cp_base.h:80
float stats[AIR_STATS_MAX]
Definition inv_shared.h:248
int installationTime
Definition inv_shared.h:252
aircraftItemType_t type
Definition inv_shared.h:247
float weaponDelay
Definition inv_shared.h:251
A installation with all it's data.
char name[MAX_VAR]
const installationTemplate_t * installationTemplate
baseWeapon_t batteries[MAX_INSTALLATION_BATTERIES]
installationStatus_t installationStatus
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition inv_shared.h:307
bool isVirtual
Definition inv_shared.h:284
int numAmmos
Definition inv_shared.h:308
craftItem craftitem
Definition inv_shared.h:331
const char * id
Definition inv_shared.h:268
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition inv_shared.h:311
const char * name
Definition inv_shared.h:267
This is the technology parsed from research.ufo.
char * provides
#define EQUAL(a, b)
Definition vector.h:37
#define xmlNode_t
Definition xml.h:24