cp_mapfightequip.c

Go to the documentation of this file.
00001 
00008 /*
00009 Copyright (C) 2002-2010 UFO: Alien Invasion.
00010 
00011 This program is free software; you can redistribute it and/or
00012 modify it under the terms of the GNU General Public License
00013 as published by the Free Software Foundation; either version 2
00014 of the License, or (at your option) any later version.
00015 
00016 This program is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00019 
00020 See the GNU General Public License for more details.
00021 
00022 You should have received a copy of the GNU General Public License
00023 along with this program; if not, write to the Free Software
00024 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00025 
00026 */
00027 
00028 #include "../cl_shared.h"
00029 #include "../ui/ui_main.h"
00030 #include "cp_campaign.h"
00031 #include "cp_mapfightequip.h"
00032 #include "cp_ufo.h"
00033 #include "cp_map.h"
00034 #include "save/save_fightequip.h"
00035 
00036 #define UFO_RELOAD_DELAY_MULTIPLIER 2
00037 #define AIRCRAFT_RELOAD_DELAY_MULTIPLIER 2
00038 #define BASE_RELOAD_DELAY_MULTIPLIER 2
00039 #define INSTALLATION_RELOAD_DELAY_MULTIPLIER 2
00040 
00046 technology_t **AII_GetCraftitemTechsByType (int type)
00047 {
00048     static technology_t *techList[MAX_TECHNOLOGIES];
00049     int i, j = 0;
00050 
00051     for (i = 0; i < csi.numODs; i++) {
00052         const objDef_t *aircraftitem = INVSH_GetItemByIDX(i);
00053         if (aircraftitem->craftitem.type == type) {
00054             technology_t *tech = RS_GetTechForItem(aircraftitem);
00055             assert(j < MAX_TECHNOLOGIES);
00056             techList[j] = tech;
00057             j++;
00058         }
00059         /* j+1 because last item has to be NULL */
00060         if (j + 1 >= MAX_TECHNOLOGIES) {
00061             Com_Printf("AII_GetCraftitemTechsByType: MAX_TECHNOLOGIES limit hit.\n");
00062             break;
00063         }
00064     }
00065     /* terminate the list */
00066     techList[j] = NULL;
00067     return techList;
00068 }
00069 
00076 itemWeight_t AII_GetItemWeightBySize (const objDef_t *od)
00077 {
00078     assert(od);
00079     assert(od->craftitem.type >= 0);
00080 
00081     if (od->size < 50)
00082         return ITEM_LIGHT;
00083     else if (od->size < 100)
00084         return ITEM_MEDIUM;
00085     else
00086         return ITEM_HEAVY;
00087 }
00088 
00095 qboolean AIM_SelectableCraftItem (const aircraftSlot_t *slot, const technology_t *tech)
00096 {
00097     objDef_t *item;
00098 
00099     if (!slot)
00100         return qfalse;
00101 
00102     if (!RS_IsResearched_ptr(tech))
00103         return qfalse;
00104 
00105     item = INVSH_GetItemByID(tech->provides);
00106     if (!item)
00107         return qfalse;
00108 
00109     if (item->craftitem.type >= AC_ITEM_AMMO) {
00110         const objDef_t *weapon = slot->item;
00111         int k;
00112         if (slot->nextItem != NULL)
00113             weapon = slot->nextItem;
00114 
00115         if (weapon == NULL)
00116             return qfalse;
00117 
00118         /* Is the ammo is usable with the slot */
00119         for (k = 0; k < weapon->numAmmos; k++) {
00120             const objDef_t *usable = weapon->ammos[k];
00121             if (usable && item->idx == usable->idx)
00122                 break;
00123         }
00124         if (k >= weapon->numAmmos)
00125             return qfalse;
00126     }
00127 
00129     if (slot->type >= AC_ITEM_AMMO) {
00132         if (!slot->nextItem && item->weapons[0] != slot->item)
00133             return qfalse;
00134 
00135         /* are we trying to change ammos for nextItem? */
00136         if (slot->nextItem && item->weapons[0] != slot->nextItem)
00137             return qfalse;
00138     }
00139 
00140     /* you can install an item only if its weight is small enough for the slot */
00141     if (AII_GetItemWeightBySize(item) > slot->size)
00142         return qfalse;
00143 
00144     /* you can't install an item that you don't possess
00145      * virtual items don't need to be possessed
00146      * installations always have weapon and ammo */
00147     if (slot->aircraft) {
00148         if (!B_BaseHasItem(slot->aircraft->homebase, item))
00149             return qfalse;
00150     } else if (slot->base) {
00151         if (!B_BaseHasItem(slot->base, item))
00152             return qfalse;
00153     }
00154 
00155     /* you can't install an item that does not have an installation time (alien item)
00156      * except for ammo which does not have installation time */
00157     if (item->craftitem.installationTime == -1 && slot->type < AC_ITEM_AMMO)
00158         return qfalse;
00159 
00160     return qtrue;
00161 }
00162 
00169 qboolean AIM_PilotAssignedAircraft (const base_t* base, const employee_t* pilot)
00170 {
00171     qboolean found = qfalse;
00172     aircraft_t *aircraft;
00173 
00174     aircraft = NULL;
00175     while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00176         if (aircraft->pilot == pilot) {
00177             found = qtrue;
00178             break;
00179         }
00180     }
00181 
00182     return found;
00183 }
00184 
00191 void BDEF_AddBattery (basedefenceType_t basedefType, base_t* base)
00192 {
00193     switch (basedefType) {
00194     case BASEDEF_MISSILE:
00195         if (base->numBatteries >= MAX_BASE_SLOT) {
00196             Com_Printf("BDEF_AddBattery: too many missile batteries in base\n");
00197             return;
00198         }
00199         if (base->numBatteries)
00200             base->batteries[base->numBatteries].autofire = base->batteries[0].autofire;
00201         else if (base->numLasers)
00202             base->batteries[base->numBatteries].autofire = base->lasers[0].autofire;
00203         else
00204             base->batteries[base->numBatteries].autofire = qtrue;
00205         base->numBatteries++;
00206         break;
00207     case BASEDEF_LASER:
00208         if (base->numLasers >= MAX_BASE_SLOT) {
00209             Com_Printf("BDEF_AddBattery: too many laser batteries in base\n");
00210             return;
00211         }
00212         base->lasers[base->numLasers].slot.ammoLeft = AMMO_STATUS_NOT_SET;
00213         if (base->numBatteries)
00214             base->lasers[base->numLasers].autofire = base->batteries[0].autofire;
00215         else if (base->numLasers)
00216             base->lasers[base->numLasers].autofire = base->lasers[0].autofire;
00217         else
00218             base->lasers[base->numLasers].autofire = qtrue;
00219         base->numLasers++;
00220         break;
00221     default:
00222         Com_Printf("BDEF_AddBattery: unknown type of base defence system.\n");
00223     }
00224 }
00225 
00235 void BDEF_RemoveBattery (base_t *base, basedefenceType_t basedefType, int idx)
00236 {
00237     int i;
00238     assert(base);
00239 
00240     /* Select the type of base defence system to destroy */
00241     switch (basedefType) {
00242     case BASEDEF_MISSILE: /* this is a missile battery */
00243         /* we must have at least one missile battery to remove it */
00244         assert(base->numBatteries > 0);
00245         /* look for an unequipped battery */
00246         if (idx < 0) {
00247             for (i = 0; i < base->numBatteries; i++) {
00248                 if (!base->batteries[i].slot.item) {
00249                     idx = i;
00250                     break;
00251                 }
00252             }
00253         }
00254         /* if none found remove the last one */
00255         if (idx < 0)
00256             idx = base->numBatteries - 1;
00257         REMOVE_ELEM(base->batteries, idx, base->numBatteries);
00258         /* just for security */
00259         AII_InitialiseSlot(&base->batteries[base->numBatteries].slot, NULL, base, NULL, AC_ITEM_BASE_MISSILE);
00260         break;
00261     case BASEDEF_LASER: /* this is a laser battery */
00262         /* we must have at least one laser battery to remove it */
00263         assert(base->numLasers > 0);
00264         /* look for an unequipped battery */
00265         if (idx < 0) {
00266             for (i = 0; i < base->numLasers; i++) {
00267                 if (!base->lasers[i].slot.item) {
00268                     idx = i;
00269                     break;
00270                 }
00271             }
00272         }
00273         /* if none found remove the last one */
00274         if (idx < 0)
00275             idx = base->numLasers - 1;
00276         REMOVE_ELEM(base->lasers, idx, base->numLasers);
00277         /* just for security */
00278         AII_InitialiseSlot(&base->lasers[base->numLasers].slot, NULL, base, NULL, AC_ITEM_BASE_LASER);
00279         break;
00280     default:
00281         Com_Printf("BDEF_RemoveBattery_f: unknown type of base defence system.\n");
00282     }
00283 }
00284 
00289 void BDEF_InitialiseBaseSlots (base_t *base)
00290 {
00291     int i;
00292 
00293     for (i = 0; i < MAX_BASE_SLOT; i++) {
00294         baseWeapon_t* battery = &base->batteries[i];
00295         baseWeapon_t* laser = &base->lasers[i];
00296         AII_InitialiseSlot(&battery->slot, NULL, base, NULL, AC_ITEM_BASE_MISSILE);
00297         AII_InitialiseSlot(&laser->slot, NULL, base, NULL, AC_ITEM_BASE_LASER);
00298         battery->autofire = qtrue;
00299         battery->target = NULL;
00300         laser->autofire = qtrue;
00301         laser->target = NULL;
00302     }
00303 }
00304 
00309 void BDEF_InitialiseInstallationSlots (installation_t *installation)
00310 {
00311     int i;
00312 
00313     for (i = 0; i < installation->installationTemplate->maxBatteries; i++) {
00314         baseWeapon_t* battery = &installation->batteries[i];
00315         AII_InitialiseSlot(&battery->slot, NULL, NULL, installation, AC_ITEM_BASE_MISSILE);
00316         battery->target = NULL;
00317         battery->autofire = qtrue;
00318     }
00319 }
00320 
00321 
00330 static void AII_UpdateOneInstallationDelay (base_t* base, installation_t* installation, aircraft_t *aircraft, aircraftSlot_t *slot)
00331 {
00332     assert(base || installation);
00333 
00334     /* if the item is already installed, nothing to do */
00335     if (slot->installationTime == 0)
00336         return;
00337     else if (slot->installationTime > 0) {
00338         /* the item is being installed */
00339         slot->installationTime--;
00340         /* check if installation is over */
00341         if (slot->installationTime <= 0) {
00342             /* Update stats values */
00343             if (aircraft) {
00344                 AII_UpdateAircraftStats(aircraft);
00345                 Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer),
00346                         _("%s was successfully installed into aircraft %s at %s."),
00347                         _(slot->item->name), aircraft->name, aircraft->homebase->name);
00348             } else if (installation) {
00349                 Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("%s was successfully installed at installation %s."),
00350                         _(slot->item->name), installation->name);
00351             } else {
00352                 Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("%s was successfully installed at %s."),
00353                         _(slot->item->name), base->name);
00354             }
00355             MSO_CheckAddNewMessage(NT_INSTALLATION_INSTALLED, _("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00356         }
00357     } else if (slot->installationTime < 0) {
00358         const objDef_t *olditem;
00359 
00360         /* the item is being removed */
00361         slot->installationTime++;
00362         if (slot->installationTime >= 0) {
00363 #ifdef DEBUG
00364             if (aircraft && aircraft->homebase != base)
00365                 Sys_Error("AII_UpdateOneInstallationDelay: aircraft->homebase and base pointers are out of sync\n");
00366 #endif
00367             olditem = slot->item;
00368             AII_RemoveItemFromSlot(base, slot, qfalse);
00369             if (aircraft) {
00370                 AII_UpdateAircraftStats(aircraft);
00371                 /* Only stop time and post a notice, if no new item to install is assigned */
00372                 if (!slot->item) {
00373                     Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer),
00374                             _("%s was successfully removed from aircraft %s at %s."),
00375                             _(olditem->name), aircraft->name, base->name);
00376                     MSO_CheckAddNewMessage(NT_INSTALLATION_REMOVED, _("Notice"), cp_messageBuffer, qfalse,
00377                             MSG_STANDARD, NULL);
00378                 } else {
00379                     Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer),
00380                             _ ("%s was successfully removed, starting installation of %s into aircraft %s at %s"),
00381                             _(olditem->name), _(slot->item->name), aircraft->name, base->name);
00382                     MSO_CheckAddNewMessage(NT_INSTALLATION_REPLACE, _("Notice"), cp_messageBuffer, qfalse,
00383                             MSG_STANDARD, NULL);
00384                 }
00385             } else if (!slot->item) {
00386                 if (installation) {
00387                     Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer),
00388                             _("%s was successfully removed from installation %s."),
00389                             _(olditem->name), installation->name);
00390                 } else {
00391                     Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("%s was successfully removed from %s."),
00392                             _(olditem->name), base->name);
00393                 }
00394                 MSO_CheckAddNewMessage(NT_INSTALLATION_REMOVED, _("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00395             }
00396         }
00397     }
00398 }
00399 
00406 void AII_UpdateInstallationDelay (void)
00407 {
00408     int j, k;
00409 
00410     for (j = 0; j < MAX_INSTALLATIONS; j++) {
00411         installation_t *installation = INS_GetFoundedInstallationByIDX(j);
00412         if (!installation)
00413             continue;
00414 
00415         /* Update base */
00416         for (k = 0; k < installation->installationTemplate->maxBatteries; k++)
00417             AII_UpdateOneInstallationDelay(NULL, installation, NULL, &installation->batteries[k].slot);
00418     }
00419 
00420     for (j = 0; j < MAX_BASES; j++) {
00421         aircraft_t *aircraft;
00422         base_t *base = B_GetFoundedBaseByIDX(j);
00423         if (!base)
00424             continue;
00425 
00426         /* Update base */
00427         for (k = 0; k < base->numBatteries; k++)
00428             AII_UpdateOneInstallationDelay(base, NULL, NULL, &base->batteries[k].slot);
00429         for (k = 0; k < base->numLasers; k++)
00430             AII_UpdateOneInstallationDelay(base, NULL, NULL, &base->lasers[k].slot);
00431 
00432         /* Update each aircraft */
00433         aircraft = NULL;
00434         while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00435             if (aircraft->homebase) {
00436                 assert(aircraft->homebase == base);
00437                 if (AIR_IsAircraftInBase(aircraft)) {
00438                     /* Update electronics delay */
00439                     for (k = 0; k < aircraft->maxElectronics; k++)
00440                         AII_UpdateOneInstallationDelay(base, NULL, aircraft, aircraft->electronics + k);
00441 
00442                     /* Update weapons delay */
00443                     for (k = 0; k < aircraft->maxWeapons; k++)
00444                         AII_UpdateOneInstallationDelay(base, NULL, aircraft, aircraft->weapons + k);
00445 
00446                     /* Update shield delay */
00447                     AII_UpdateOneInstallationDelay(base, NULL, aircraft, &aircraft->shield);
00448                 }
00449             }
00450         }
00451     }
00452 }
00453 
00460 void AII_AutoAddAmmo (aircraftSlot_t *slot)
00461 {
00462     int k;
00463     const objDef_t *item;
00464 
00465     assert(slot);
00466 
00467     /* Get the weapon (either current weapon or weapon to install after this one is removed) */
00468     item = slot->nextItem ? slot->nextItem : slot->item;
00469     /* no items assigned */
00470     if (!item)
00471         return;
00472     /* item not a weapon */
00473     if (item->craftitem.type > AC_ITEM_WEAPON)
00474         return;
00475     /* don't try to add ammo to a slot that already has ammo */
00476     if (slot->nextItem ? slot->nextAmmo : slot->ammo)
00477         return;
00478     /* Try every ammo usable with this weapon until we find one we have in storage */
00479     for (k = 0; k < item->numAmmos; k++) {
00480         const objDef_t *ammo = item->ammos[k];
00481         if (ammo) {
00482             const technology_t *ammoTech = RS_GetTechForItem(ammo);
00483             if (AIM_SelectableCraftItem(slot, ammoTech)) {
00484                 base_t* base;
00485                 if (ammo->isVirtual)
00486                     base = NULL;
00487                 else if (slot->aircraft)
00488                     base = slot->aircraft->homebase;
00489                 else
00490                     base = slot->base;
00491                 AII_AddAmmoToSlot(base, ammoTech, slot);
00492                 break;
00493             }
00494         }
00495     }
00496 }
00497 
00509 void AII_RemoveItemFromSlot (base_t* base, aircraftSlot_t *slot, qboolean ammo)
00510 {
00511     assert(slot);
00512 
00513     if (ammo) {
00514         /* only remove the ammo */
00515         if (slot->ammo) {
00516             /* Can only remove non-virtual ammo */
00517             if (!slot->ammo->isVirtual) {
00518                 if (base)
00519                     B_UpdateStorageAndCapacity(base, slot->ammo, 1, qfalse, qfalse);
00520                 slot->ammo = NULL;
00521                 slot->ammoLeft = 0;
00522             }
00523         }
00524     } else if (slot->item) {
00525         /* remove ammo */
00526         AII_RemoveItemFromSlot(base, slot, qtrue);
00527         if (!slot->item->isVirtual) {
00528             if (base)
00529                 B_UpdateStorageAndCapacity(base, slot->item, 1, qfalse, qfalse);
00530             /* the removal is over */
00531             if (slot->nextItem) {
00532                 /* there is anoter item to install after this one */
00533                 slot->item = slot->nextItem;
00534                 /* we already removed nextItem from storage when it has been added to slot: don't use B_UpdateStorageAndCapacity */
00535                 slot->ammo = slot->nextAmmo;
00536                 if (slot->ammo)
00537                     slot->ammoLeft = slot->ammo->ammo;
00538                 slot->installationTime = slot->item->craftitem.installationTime;
00539                 slot->nextItem = NULL;
00540                 slot->nextAmmo = NULL;
00541             } else {
00542                 slot->item = NULL;
00543                 /* make sure nextAmmo is removed too
00544                  * virtual ammos cannot be removed without the weapon itself */
00545                 slot->ammo = NULL;
00546                 slot->ammoLeft = 0;
00547                 slot->installationTime = 0;
00548             }
00549         }
00550     }
00551 }
00552 
00562 void AII_RemoveNextItemFromSlot (base_t* base, aircraftSlot_t *slot, qboolean ammo)
00563 {
00564     assert(slot);
00565 
00566     if (ammo) {
00567         /* only remove the ammo */
00568         if (slot->nextAmmo) {
00569             if (!slot->nextAmmo->isVirtual) {
00570                 if (base)
00571                     B_UpdateStorageAndCapacity(base, slot->nextAmmo, 1, qfalse, qfalse);
00572                 slot->nextAmmo = NULL;
00573             }
00574         }
00575     } else if (slot->nextItem) {
00576         /* Remove nextItem */
00577         if (base)
00578             B_UpdateStorageAndCapacity(base, slot->nextItem, 1, qfalse, qfalse);
00579         slot->nextItem = NULL;
00580         /* also remove ammo if any */
00581         if (slot->nextAmmo)
00582             AII_RemoveNextItemFromSlot(base, slot, qtrue);
00583         /* make sure nextAmmo is removed too
00584          * virtual ammos cannot be removed without the weapon itself */
00585         slot->nextAmmo = NULL;
00586     }
00587 }
00588 
00594 qboolean AII_ReloadWeapon (aircraftSlot_t *slot)
00595 {
00596     assert(slot);
00597 
00598     /* no weapon assigned - failure */
00599     if (!slot->item)
00600         return qfalse;
00601     /* no ammo assigned - try adding one */
00602     if (!slot->ammo)
00603         AII_AutoAddAmmo(slot);
00604     /* still no ammo assigned - failure */
00605     if (!slot->ammo)
00606         return qfalse;
00607     /* no reload needed - success */
00608     if (slot->ammoLeft >= slot->ammo->ammo)
00609         return qtrue;
00610 
00611     if (slot->aircraft) {
00612         /* PHALANX aircraft and UFO crafts */
00613         if (AIR_IsUFO(slot->aircraft)) {
00614             /* UFO - can always be reloaded */
00615             slot->ammoLeft = slot->ammo->ammo;
00616             slot->delayNextShot = slot->ammo->craftitem.weaponDelay * UFO_RELOAD_DELAY_MULTIPLIER;
00617         } else {
00618             /* PHALANX aircraft */
00619             /* not at home */
00620             if (!AIR_IsAircraftInBase(slot->aircraft))
00621                 return qfalse;
00622             /* no more ammo available */
00623             if (!B_BaseHasItem(slot->aircraft->homebase, slot->ammo))
00624                 return qfalse;
00625 
00626             B_UpdateStorageAndCapacity(slot->aircraft->homebase, slot->ammo, -1, qfalse, qfalse);
00627             slot->ammoLeft = slot->ammo->ammo;
00628             slot->delayNextShot = slot->ammo->craftitem.weaponDelay * AIRCRAFT_RELOAD_DELAY_MULTIPLIER;
00629         }
00630     } else if (slot->base) {
00631         /* Base Defence weapons */
00632         /* no more ammo available */
00633         if (!B_BaseHasItem(slot->base, slot->ammo))
00634             return qfalse;
00635 
00636         B_UpdateStorageAndCapacity(slot->base, slot->ammo, -1, qfalse, qfalse);
00637         slot->ammoLeft = slot->ammo->ammo;
00638         slot->delayNextShot = slot->ammo->craftitem.weaponDelay * BASE_RELOAD_DELAY_MULTIPLIER;
00639     } else if (slot->installation) {
00640         /* Installations (SAM-Sites) - can always be reloaded. */
00641         slot->ammoLeft = slot->ammo->ammo;
00642         slot->delayNextShot = slot->ammo->craftitem.weaponDelay * INSTALLATION_RELOAD_DELAY_MULTIPLIER;
00643     } else {
00644         Com_Error(ERR_DROP, "AII_ReloadWeapon: AircraftSlot not linked anywhere (aircraft/base/installation)!\n");
00645     }
00646     return qtrue;
00647 }
00648 
00653 void AII_ReloadAircraftWeapons (aircraft_t *aircraft)
00654 {
00655     int i;
00656 
00657     assert(aircraft);
00658     /* Reload all ammos of aircraft */
00659     for (i = 0; i < aircraft->maxWeapons; i++) {
00660         AII_ReloadWeapon(&aircraft->weapons[i]);
00661     }
00662 }
00663 
00670 void BDEF_ReloadBaseWeapons (base_t *base, installation_t *installation)
00671 {
00672     int i;
00673 
00674     if (base && installation)
00675         Com_Error(ERR_DROP, "BDEF_ReloadBattery: Both base and Installation pointer set!\n");
00676     if (!(base || installation))
00677         Com_Error(ERR_DROP, "BDEF_ReloadBattery: Neither base nor Installation pointer set!\n");
00678 
00679     if (base) {
00680         for (i = 0; i < base->numBatteries; i++) {
00681             AII_ReloadWeapon(&(base->batteries[i].slot));
00682         }
00683         for (i = 0; i < base->numLasers; i++) {
00684             AII_ReloadWeapon(&(base->lasers[i].slot));
00685         }
00686     } else if (installation) {
00687         for (i = 0; i < installation->numBatteries; i++) {
00688             AII_ReloadWeapon(&(installation->batteries[i].slot));
00689         }
00690     }
00691 }
00692 
00701 qboolean AII_AddAmmoToSlot (base_t* base, const technology_t *tech, aircraftSlot_t *slot)
00702 {
00703     const objDef_t *ammo;
00704     const objDef_t *item;
00705     int k;
00706 
00707     if (slot == NULL || slot->item == NULL)
00708         return qfalse;
00709 
00710     assert(tech);
00711 
00712     ammo = INVSH_GetItemByID(tech->provides);
00713     if (!ammo) {
00714         Com_Printf("AII_AddAmmoToSlot: Could not add item (%s) to slot\n", tech->provides);
00715         return qfalse;
00716     }
00717 
00718     item = (slot->nextItem) ? slot->nextItem : slot->item;
00719 
00720     /* Is the ammo is usable with the slot */
00721     for (k = 0; k < item->numAmmos; k++) {
00722         const objDef_t *usable = item->ammos[k];
00723         if (usable && ammo->idx == usable->idx)
00724             break;
00725     }
00726     if (k >= item->numAmmos)
00727         return qfalse;
00728 
00729     /* the base pointer can be null here - e.g. in case you are equipping a UFO
00730      * and base ammo defence are not stored in storage */
00731     if (base && ammo->craftitem.type <= AC_ITEM_AMMO) {
00732         if (!B_BaseHasItem(base, ammo)) {
00733             Com_Printf("AII_AddAmmoToSlot: No more ammo of this type to equip (%s)\n", ammo->id);
00734             return qfalse;
00735         }
00736     }
00737 
00738     /* remove any applied ammo in the current slot */
00739     if (slot->nextItem) {
00740         if (slot->nextAmmo)
00741             AII_RemoveNextItemFromSlot(base, slot, qtrue);
00742         /* ammo couldn't be removed (maybe it's virtual) */
00743         if (slot->nextAmmo)
00744             return qfalse;
00745         slot->nextAmmo = ammo;
00746     } else {
00747         /* you shouldn't be able to have nextAmmo set if you don't have nextItem set */
00748         assert(!slot->nextAmmo);
00749         AII_RemoveItemFromSlot(base, slot, qtrue);
00750         /* ammo couldn't be removed (maybe it's virtual) */
00751         if (slot->ammo)
00752             return qfalse;
00753         slot->ammo = ammo;
00754     }
00755 
00756     /* proceed only if we are changing ammo of current weapon */
00757     if (slot->nextItem) {
00758         /* the base pointer can be null here - e.g. in case you are equipping a UFO */
00759         if (base)
00760             B_UpdateStorageAndCapacity(base, ammo, -1, qfalse, qfalse);
00761         return qtrue;
00762     }
00763     AII_ReloadWeapon(slot);
00764 
00765     return qtrue;
00766 }
00767 
00779 qboolean AII_AddItemToSlot (base_t *base, const technology_t *tech, aircraftSlot_t *slot, qboolean nextItem)
00780 {
00781     const objDef_t *item;
00782 
00783     assert(slot);
00784     assert(tech);
00785 
00786     item = INVSH_GetItemByID(tech->provides);
00787     if (!item) {
00788         Com_Printf("AII_AddItemToSlot: Could not add item (%s) to slot\n", tech->provides);
00789         return qfalse;
00790     }
00791 
00792 #ifdef DEBUG
00793     /* Sanity check : the type of the item cannot be an ammo */
00794     /* note that this should never be reached because a slot type should never be an ammo
00795      * , so the test just before should be wrong */
00796     if (item->craftitem.type >= AC_ITEM_AMMO) {
00797         Com_Printf("AII_AddItemToSlot: Type of the item to install (%s) should be a weapon, a shield, or electronics (no ammo)\n", item->id);
00798         return qfalse;
00799     }
00800 #endif
00801 
00802     /* Sanity check : the type of the item should be the same than the slot type */
00803     if (slot->type != item->craftitem.type) {
00804         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);
00805         return qfalse;
00806     }
00807 
00808     /* the base pointer can be null here - e.g. in case you are equipping a UFO */
00809     if (base && !B_BaseHasItem(base, item)) {
00810         Com_Printf("AII_AddItemToSlot: No more item of this type to equip (%s)\n", item->id);
00811         return qfalse;
00812     }
00813 
00814     if (slot->size >= AII_GetItemWeightBySize(item)) {
00815         if (nextItem)
00816             slot->nextItem = item;
00817         else {
00818             slot->item = item;
00819             slot->installationTime = item->craftitem.installationTime;
00820         }
00821         /* the base pointer can be null here - e.g. in case you are equipping a UFO
00822          * Remove item even for nextItem, this way we are sure we won't use the same item
00823          * for another aircraft. */
00824         if (base)
00825             B_UpdateStorageAndCapacity(base, item, -1, qfalse, qfalse);
00826     } else {
00827         Com_Printf("AII_AddItemToSlot: Could not add item '%s' to slot %i (slot-size: %i - item-weight: %i)\n",
00828             item->id, slot->idx, slot->size, item->size);
00829         return qfalse;
00830     }
00831 
00832     return qtrue;
00833 }
00834 
00841 void AIM_AutoEquipAircraft (aircraft_t *aircraft)
00842 {
00843     int i;
00844     objDef_t *item;
00846     const technology_t *tech = RS_GetTechByID("rs_craft_weapon_sparrowhawk");
00847 
00848     if (!tech)
00849         Com_Error(ERR_DROP, "Could not get tech rs_craft_weapon_sparrowhawk");
00850 
00851     assert(aircraft);
00852     assert(aircraft->homebase);
00853 
00854     item = INVSH_GetItemByID(tech->provides);
00855     if (!item)
00856         return;
00857 
00858     for (i = 0; i < aircraft->maxWeapons; i++) {
00859         aircraftSlot_t *slot = &aircraft->weapons[i];
00860         if (slot->size < AII_GetItemWeightBySize(item))
00861             continue;
00862         if (!B_BaseHasItem(aircraft->homebase, item))
00863             continue;
00864         AII_AddItemToSlot(aircraft->homebase, tech, slot, qfalse);
00865         AII_AutoAddAmmo(slot);
00866         slot->installationTime = 0;
00867     }
00868 
00869     /* Fill slots too small for sparrowhawk with shiva */
00870     tech = RS_GetTechByID("rs_craft_weapon_shiva");
00871 
00872     if (!tech)
00873         Com_Error(ERR_DROP, "Could not get tech rs_craft_weapon_shiva");
00874 
00875     item = INVSH_GetItemByID(tech->provides);
00876 
00877     if (!item)
00878         return;
00879 
00880     for (i = 0; i < aircraft->maxWeapons; i++) {
00881         aircraftSlot_t *slot = &aircraft->weapons[i];
00882         if (slot->size < AII_GetItemWeightBySize(item))
00883             continue;
00884         if (!B_BaseHasItem(aircraft->homebase, item))
00885             continue;
00886         if (slot->item)
00887             continue;
00888         AII_AddItemToSlot(aircraft->homebase, tech, slot, qfalse);
00889         AII_AutoAddAmmo(slot);
00890         slot->installationTime = 0;
00891     }
00892 
00893     AII_UpdateAircraftStats(aircraft);
00894 }
00895 
00904 void AII_InitialiseSlot (aircraftSlot_t *slot, aircraft_t *aircraftTemplate, base_t *base, installation_t *installation, aircraftItemType_t type)
00905 {
00906     /* Only one of them is allowed. */
00907     assert((!base && aircraftTemplate) || (base && !aircraftTemplate) || (installation && !aircraftTemplate));
00908     /* Only one of them is allowed or neither. */
00909     assert((!base && installation) || (base && !installation) || (!base && !installation));
00910 
00911     memset(slot, 0, sizeof(slot));
00912     slot->aircraft = aircraftTemplate;
00913     slot->base = base;
00914     slot->installation = installation;
00915     slot->item = NULL;
00916     slot->ammo = NULL;
00917     slot->nextAmmo = NULL;
00918     slot->size = ITEM_HEAVY;
00919     slot->nextItem = NULL;
00920     slot->type = type;
00922     slot->ammoLeft = AMMO_STATUS_NOT_SET;
00923     slot->installationTime = 0;
00924 }
00925 
00932 static qboolean AII_CheckUpdateAircraftStats (const aircraftSlot_t *slot, int stat)
00933 {
00934     assert(slot);
00935 
00936     /* there's no item */
00937     if (!slot->item)
00938         return qfalse;
00939 
00940     /* you can not have advantages from items if it is being installed or removed, but only disavantages */
00941     if (slot->installationTime != 0) {
00942         const objDef_t *item = slot->item;
00943         if (item->craftitem.stats[stat] > 1.0f) /* advantages for relative and absolute values */
00944             return qfalse;
00945     }
00946 
00947     return qtrue;
00948 }
00949 
00957 aircraftSlot_t *BDEF_GetBaseSlotByIDX (base_t *base, aircraftItemType_t type, int idx)
00958 {
00959     switch (type) {
00960     case AC_ITEM_BASE_MISSILE:
00961         if (idx < 0) {          /* returns the first free slot on negative */
00962             int i;
00963             for (i = 0; i < base->numBatteries; i++)
00964                 if (!base->batteries[i].slot.item && !base->batteries[i].slot.nextItem)
00965                     return &base->batteries[i].slot;
00966         } else if (idx < base->numBatteries)
00967             return &base->batteries[idx].slot;
00968         break;
00969     case AC_ITEM_BASE_LASER:
00970         if (idx < 0) {          /* returns the first free slot on negative */
00971             int i;
00972             for (i = 0; i < base->numLasers; i++)
00973                 if (!base->lasers[i].slot.item && !base->lasers[i].slot.nextItem)
00974                     return &base->lasers[i].slot;
00975         } else if (idx < base->numLasers)
00976             return &base->lasers[idx].slot;
00977         break;
00978     default:
00979         break;
00980     }
00981     return NULL;
00982 }
00983 
00991 aircraftSlot_t *BDEF_GetInstallationSlotByIDX (installation_t *installation, aircraftItemType_t type, int idx)
00992 {
00993     switch (type) {
00994     case AC_ITEM_BASE_MISSILE:
00995         if (idx < 0) {          /* returns the first free slot on negative */
00996             int i;
00997             for (i = 0; i < installation->numBatteries; i++)
00998                 if (!installation->batteries[i].slot.item && !installation->batteries[i].slot.nextItem)
00999                     return &installation->batteries[i].slot;
01000         } else if (idx < installation->numBatteries)
01001             return &installation->batteries[idx].slot;
01002         break;
01003     default:
01004         break;
01005     }
01006     return NULL;
01007 }
01008 
01016 aircraftSlot_t *AII_GetAircraftSlotByIDX (aircraft_t *aircraft, aircraftItemType_t type, int idx)
01017 {
01018     switch (type) {
01019     case AC_ITEM_WEAPON:
01020         if (idx < 0) {          /* returns the first free slot on negative */
01021             int i;
01022             for (i = 0; i < aircraft->maxWeapons; i++)
01023                 if (!aircraft->weapons[i].item && !aircraft->weapons[i].nextItem)
01024                     return &aircraft->weapons[i];
01025         } else if (idx < aircraft->maxWeapons)
01026             return &aircraft->weapons[idx];
01027         break;
01028     case AC_ITEM_SHIELD:
01029         if (idx == 0 || ((idx < 0) && !aircraft->shield.item && !aircraft->shield.nextItem))    /* returns the first free slot on negative */
01030             return &aircraft->shield;
01031         break;
01032     case AC_ITEM_ELECTRONICS:
01033         if (idx < 0) {          /* returns the first free slot on negative */
01034             int i;
01035             for (i = 0; i < aircraft->maxElectronics; i++)
01036                 if (!aircraft->electronics[i].item && !aircraft->electronics[i].nextItem)
01037                     return &aircraft->electronics[i];
01038         } else if (idx < aircraft->maxElectronics)
01039             return &aircraft->electronics[idx];
01040         break;
01041     default:
01042         break;
01043     }
01044     return NULL;
01045 }
01046 
01047 
01054 float AIR_GetMaxAircraftWeaponRange (const aircraftSlot_t *slot, int maxSlot)
01055 {
01056     int i;
01057     float range = 0.0f;
01058 
01059     assert(slot);
01060 
01061     /* We choose the usable weapon with the biggest range */
01062     for (i = 0; i < maxSlot; i++) {
01063         const aircraftSlot_t *weapon = slot + i;
01064         const objDef_t *ammo = weapon->ammo;
01065 
01066         if (!ammo)
01067             continue;
01068 
01069         /* make sure this item is useable */
01070         if (!AII_CheckUpdateAircraftStats(slot, AIR_STATS_WRANGE))
01071             continue;
01072 
01073         /* select this weapon if this is the one with the longest range */
01074         if (ammo->craftitem.stats[AIR_STATS_WRANGE] > range) {
01075             range = ammo->craftitem.stats[AIR_STATS_WRANGE];
01076         }
01077     }
01078     return range;
01079 }
01080 
01085 void AII_RepairAircraft (void)
01086 {
01087     int baseIDX;
01088     const int REPAIR_PER_HOUR = 1;  
01090     for (baseIDX = 0; baseIDX < MAX_BASES; baseIDX++) {
01091         base_t *base = B_GetFoundedBaseByIDX(baseIDX);
01092         aircraft_t *aircraft;
01093 
01094         aircraft = NULL;
01095         while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
01096             if (!AIR_IsAircraftInBase(aircraft))
01097                 continue;
01098             aircraft->damage = min(aircraft->damage + REPAIR_PER_HOUR, aircraft->stats[AIR_STATS_DAMAGE]);
01099         }
01100     }
01101 }
01102 
01108 void AII_UpdateAircraftStats (aircraft_t *aircraft)
01109 {
01110     int i, currentStat;
01111     const aircraft_t *source;
01112     const objDef_t *item;
01113 
01114     assert(aircraft);
01115 
01116     source = aircraft->tpl;
01117 
01118     for (currentStat = 0; currentStat < AIR_STATS_MAX; currentStat++) {
01119         /* we scan all the stats except AIR_STATS_WRANGE (see below) */
01120         if (currentStat == AIR_STATS_WRANGE)
01121             continue;
01122 
01123         /* initialise value */
01124         aircraft->stats[currentStat] = source->stats[currentStat];
01125 
01126         /* modify by electronics (do nothing if the value of stat is 0) */
01127         for (i = 0; i < aircraft->maxElectronics; i++) {
01128             if (!AII_CheckUpdateAircraftStats(&aircraft->electronics[i], currentStat))
01129                 continue;
01130             item = aircraft->electronics[i].item;
01131             if (fabs(item->craftitem.stats[currentStat]) > 2.0f)
01132                 aircraft->stats[currentStat] += (int) item->craftitem.stats[currentStat];
01133             else if (!equal(item->craftitem.stats[currentStat], 0))
01134                 aircraft->stats[currentStat] *= item->craftitem.stats[currentStat];
01135         }
01136 
01137         /* modify by weapons (do nothing if the value of stat is 0)
01138          * note that stats are not modified by ammos */
01139         for (i = 0; i < aircraft->maxWeapons; i++) {
01140             if (!AII_CheckUpdateAircraftStats(&aircraft->weapons[i], currentStat))
01141                 continue;
01142             item = aircraft->weapons[i].item;
01143             if (fabs(item->craftitem.stats[currentStat]) > 2.0f)
01144                 aircraft->stats[currentStat] += item->craftitem.stats[currentStat];
01145             else if (!equal(item->craftitem.stats[currentStat], 0))
01146                 aircraft->stats[currentStat] *= item->craftitem.stats[currentStat];
01147         }
01148 
01149         /* modify by shield (do nothing if the value of stat is 0) */
01150         if (AII_CheckUpdateAircraftStats(&aircraft->shield, currentStat)) {
01151             item = aircraft->shield.item;
01152             if (fabs(item->craftitem.stats[currentStat]) > 2.0f)
01153                 aircraft->stats[currentStat] += item->craftitem.stats[currentStat];
01154             else if (!equal(item->craftitem.stats[currentStat], 0))
01155                 aircraft->stats[currentStat] *= item->craftitem.stats[currentStat];
01156         }
01157     }
01158 
01159     /* now we update AIR_STATS_WRANGE (this one is the biggest range of every ammo) */
01160     aircraft->stats[AIR_STATS_WRANGE] = 1000.0f * AIR_GetMaxAircraftWeaponRange(aircraft->weapons, aircraft->maxWeapons);
01161 
01162     /* check that aircraft hasn't too much fuel (caused by removal of fuel pod) */
01163     if (aircraft->fuel > aircraft->stats[AIR_STATS_FUELSIZE])
01164         aircraft->fuel = aircraft->stats[AIR_STATS_FUELSIZE];
01165 
01166     /* check that aircraft hasn't too much HP (caused by removal of armour) */
01167     if (aircraft->damage > aircraft->stats[AIR_STATS_DAMAGE])
01168         aircraft->damage = aircraft->stats[AIR_STATS_DAMAGE];
01169 
01170     /* check that speed of the aircraft is positive */
01171     if (aircraft->stats[AIR_STATS_SPEED] < 1)
01172         aircraft->stats[AIR_STATS_SPEED] = 1;
01173 
01174     /* Update aircraft state if needed */
01175     if (aircraft->status == AIR_HOME && aircraft->fuel < aircraft->stats[AIR_STATS_FUELSIZE])
01176         aircraft->status = AIR_REFUEL;
01177 }
01178 
01186 static qboolean AII_WeaponsCanShoot (const baseWeapon_t *weapons, int numWeapons)
01187 {
01188     int i;
01189 
01190     for (i = 0; i < numWeapons; i++) {
01191         if (AIRFIGHT_CheckWeapon(&weapons[i].slot, 0) != AIRFIGHT_WEAPON_CAN_NEVER_SHOOT)
01192             return qtrue;
01193     }
01194 
01195     return qfalse;
01196 }
01197 
01204 int AII_BaseCanShoot (const base_t *base)
01205 {
01206     assert(base);
01207 
01208     /* If we can shoot with missile defences */
01209     if (B_GetBuildingStatus(base, B_DEFENCE_MISSILE)
01210      && AII_WeaponsCanShoot(base->batteries, base->numBatteries))
01211         return qtrue;
01212 
01213     /* If we can shoot with beam defences */
01214     if (B_GetBuildingStatus(base, B_DEFENCE_LASER)
01215      && AII_WeaponsCanShoot(base->lasers, base->numLasers))
01216         return qtrue;
01217 
01218     return qfalse;
01219 }
01220 
01227 qboolean AII_InstallationCanShoot (const installation_t *installation)
01228 {
01229     assert(installation);
01230 
01231     if (installation->founded && installation->installationStatus == INSTALLATION_WORKING
01232      && installation->installationTemplate->maxBatteries > 0) {
01233         /* installation is working and has battery */
01234         return AII_WeaponsCanShoot(installation->batteries, installation->installationTemplate->maxBatteries);
01235     }
01236 
01237     return qfalse;
01238 }
01239 
01245 static void BDEF_AutoTarget (baseWeapon_t *weapons, int maxWeapons)
01246 {
01247     const installation_t *inst;
01248     const base_t *base;
01249     aircraft_t *closestCraft = NULL;
01250     float minCraftDistance = -1;
01251     aircraft_t *closestAttacker = NULL;
01252     float minAttackerDistance = -1;
01253     const aircraftSlot_t *slot;
01254     int i;
01255 
01256     if (maxWeapons <= 0)
01257         return;
01258 
01259     slot = &weapons[0].slot;
01261     if (slot->installation) {
01262         inst = slot->installation;
01263         base = NULL;
01264     } else if (slot->base) {
01265         base = slot->base;
01266         inst = NULL;
01267     } else
01268         Com_Error(ERR_DROP, "BDEF_AutoSelectTarget: slot doesn't belong to any base or installation");
01269 
01271     for (i = 0; i < ccs.numUFOs; i++) {
01272         aircraft_t *ufo = &ccs.ufos[i];
01273         float distance;
01274 
01275         if (!UFO_IsUFOSeenOnGeoscape(ufo))
01276             continue;
01277         distance = GetDistanceOnGlobe(inst ? inst->pos : base->pos, ufo->pos);
01278         if (minCraftDistance < 0 || minCraftDistance > distance) {
01279             minCraftDistance = distance;
01280             closestCraft = ufo;
01281         }
01282         if ((minAttackerDistance < 0 || minAttackerDistance > distance) && ufo->mission
01283          && ((base && ufo->mission->category == INTERESTCATEGORY_BASE_ATTACK && ufo->mission->data == base)
01284          || (inst && ufo->mission->category == INTERESTCATEGORY_INTERCEPT && ufo->mission->data == inst))) {
01285             minAttackerDistance = distance;
01286             closestAttacker = ufo;
01287         }
01288     }
01289 
01291     for (i = 0; i < maxWeapons; i++) {
01292         slot = &weapons[i].slot;
01294         if (!weapons[i].autofire)
01295             continue;
01297         if (!slot->item || !slot->ammo)
01298             continue;
01300         if (slot->installationTime > 0)
01301             continue;
01304         if (slot->ammoLeft <= 0)
01305             continue;
01306 
01307         if (closestAttacker) {
01308             const int test = AIRFIGHT_CheckWeapon(slot, minAttackerDistance);
01309             if (test != AIRFIGHT_WEAPON_CAN_NEVER_SHOOT
01310              && test != AIRFIGHT_WEAPON_CAN_NOT_SHOOT_AT_THE_MOMENT
01311              && (minAttackerDistance <= slot->ammo->craftitem.stats[AIR_STATS_WRANGE]))
01312                 weapons[i].target = closestAttacker;
01313         } else if (closestCraft) {
01314             const int test = AIRFIGHT_CheckWeapon(slot, minCraftDistance);
01315             if (test != AIRFIGHT_WEAPON_CAN_NEVER_SHOOT
01316              && test != AIRFIGHT_WEAPON_CAN_NOT_SHOOT_AT_THE_MOMENT
01317              && (minCraftDistance <= slot->ammo->craftitem.stats[AIR_STATS_WRANGE]))
01318                 weapons[i].target = closestCraft;
01319         }
01320     }
01321 }
01322 
01326 void BDEF_AutoSelectTarget (void)
01327 {
01328     int i;
01329 
01330     for (i = 0; i < ccs.numBases; i++) {
01331         base_t *base = B_GetFoundedBaseByIDX(i);
01332         if (!base)
01333             continue;
01334 
01335         BDEF_AutoTarget(base->batteries, base->numBatteries);
01336         BDEF_AutoTarget(base->lasers, base->numLasers);
01337     }
01338 
01339     for (i = 0; i < ccs.numInstallations; i++) {
01340         installation_t *inst = INS_GetFoundedInstallationByIDX(i);
01341         if (!inst)
01342             continue;
01343 
01344         BDEF_AutoTarget(inst->batteries, inst->numBatteries);
01345     }
01346 }
01347 
01353 const char* AII_WeightToName (itemWeight_t weight)
01354 {
01355     switch (weight) {
01356     case ITEM_LIGHT:
01357         return _("Light weight");
01358         break;
01359     case ITEM_MEDIUM:
01360         return _("Medium weight");
01361         break;
01362     case ITEM_HEAVY:
01363         return _("Heavy weight");
01364         break;
01365     default:
01366         return _("Unknown weight");
01367         break;
01368     }
01369 }
01370 
01377 void AII_SaveOneSlotXML (mxml_node_t *p, const aircraftSlot_t* slot, qboolean weapon)
01378 {
01379     mxml_AddStringValue(p, SAVE_SLOT_ITEMID, slot->item ? slot->item->id : "");
01380     mxml_AddStringValue(p, SAVE_SLOT_NEXTITEMID, slot->nextItem ? slot->nextItem->id : "");
01381     mxml_AddIntValue(p, SAVE_SLOT_INSTALLATIONTIME, slot->installationTime);
01382 
01383     /* everything below is only for weapon */
01384     if (!weapon)
01385         return;
01386 
01387     mxml_AddIntValue(p, SAVE_SLOT_AMMOLEFT, slot->ammoLeft);
01388     mxml_AddStringValue(p, SAVE_SLOT_AMMOID, slot->ammo ? slot->ammo->id : "");
01389     mxml_AddStringValue(p, SAVE_SLOT_NEXTAMMOID, slot->nextAmmo ? slot->nextAmmo->id : "");
01390     mxml_AddIntValue(p, SAVE_SLOT_DELAYNEXTSHOT, slot->delayNextShot);
01391 }
01392 
01401 void AII_LoadOneSlotXML (mxml_node_t *node, aircraftSlot_t* slot, qboolean weapon)
01402 {
01403     const char *name;
01404     name = mxml_GetString(node, SAVE_SLOT_ITEMID);
01405     if (name[0] != '\0') {
01406         technology_t *tech = RS_GetTechByProvided(name);
01407         /* base is NULL here to not check against the storage amounts - they
01408         * are already loaded in the campaign load function and set to the value
01409         * after the craftitem was already removed from the initial game - thus
01410         * there might not be any of these items in the storage at this point.
01411         * Furthermore, they have already be taken from storage during game. */
01412         if (tech)
01413             AII_AddItemToSlot(NULL, tech, slot, qfalse);
01414     }
01415 
01416     /* item to install after current one is removed */
01417     name = mxml_GetString(node, SAVE_SLOT_NEXTITEMID);
01418     if (name && name[0] != '\0') {
01419         technology_t *tech = RS_GetTechByProvided(name);
01420         if (tech)
01421             AII_AddItemToSlot(NULL, tech, slot, qtrue);
01422     }
01423 
01424     slot->installationTime = mxml_GetInt(node, SAVE_SLOT_INSTALLATIONTIME, 0);
01425 
01426     /* everything below is weapon specific */
01427     if (!weapon)
01428         return;
01429 
01430     /* current ammo */
01431     /* load ammoLeft before adding ammo to avoid unnecessary auto-reloading */
01432     slot->ammoLeft = mxml_GetInt(node, SAVE_SLOT_AMMOLEFT, 0);
01433     name = mxml_GetString(node, SAVE_SLOT_AMMOID);
01434     if (name && name[0] != '\0') {
01435         technology_t *tech = RS_GetTechByProvided(name);
01436         /* next Item must not be loaded yet in order to install ammo properly */
01437         if (tech)
01438             AII_AddAmmoToSlot(NULL, tech, slot);
01439     }
01440     /* ammo to install after current one is removed */
01441     name = mxml_GetString(node, SAVE_SLOT_NEXTAMMOID);
01442     if (name && name[0] != '\0') {
01443         technology_t *tech = RS_GetTechByProvided(name);
01444         if (tech)
01445             AII_AddAmmoToSlot(NULL, tech, slot);
01446     }
01447     slot->delayNextShot = mxml_GetInt(node, SAVE_SLOT_DELAYNEXTSHOT, 0);
01448 }
01449 

Generated by  doxygen 1.6.2