/** * @todo It is a generic function, we can move it into cp_mapfightequip.c * @param[in] slot Pointer to an aircraft slot (can be base/installation too) * @param[in] tech Pointer to the technology to test * @return The status of the technology versus the slot */ static int AIM_CheckTechnologyIntoSlot (const aircraftSlot_t *slot, const technology_t *tech) { const objDef_t *item; if (!tech) return AIM_LOADING_NOTECHNOLOGYSELECTED; if (!slot) return AIM_LOADING_NOSLOTSELECTED; if (!RS_IsResearched_ptr(tech)) return AIM_LOADING_TECHNOLOGYNOTRESEARCHED; item = INVSH_GetItemByID(tech->provides); if (!item) return AIM_LOADING_NOTECHNOLOGYSELECTED; if (item->craftitem.type >= AC_ITEM_AMMO) { const objDef_t *weapon = slot->item; int k; if (slot->nextItem != NULL) weapon = slot->nextItem; if (weapon == NULL) return AIM_LOADING_NOWEAPON; /* Is the ammo is usable with the slot */ for (k = 0; k < weapon->numAmmos; k++) { const objDef_t *usable = weapon->ammos[k]; if (usable && item->idx == usable->idx) break; } if (k >= weapon->numAmmos) return AIM_LOADING_NOTUSABLEWITHWEAPON; #if 0 /** @todo This only works for ammo that is useable in exactly one weapon * check the weap_idx array and not only the first value */ if (!slot->nextItem && item->weapons[0] != slot->item) return AIM_LOADING_UNKNOWNPROBLEM; /* are we trying to change ammos for nextItem? */ if (slot->nextItem && item->weapons[0] != slot->nextItem) return AIM_LOADING_UNKNOWNPROBLEM; #endif } /* you can install an item only if its weight is small enough for the slot */ if (AII_GetItemWeightBySize(item) > slot->size) return AIM_LOADING_TOOHEAVY; /* you can't install an item that you don't possess * virtual ammo don't need to be possessed * installations always have weapon and ammo */ if (slot->aircraft) { if (!B_BaseHasItem(slot->aircraft->homebase, item)) return AIM_LOADING_UNKNOWNPROBLEM; } else if (slot->base) { if (!B_BaseHasItem(slot->base, item)) return AIM_LOADING_UNKNOWNPROBLEM; } /* you can't install an item that does not have an installation time (alien item) * except for ammo which does not have installation time */ if (item->craftitem.installationTime == -1 && slot->type < AC_ITEM_AMMO) return AIM_LOADING_ALIENTECH; return AIM_LOADING_OK; }
/** * @brief Prints the (UFOpaedia and other) description for aircraft items * @param item The object definition of the item * @sa UP_Article * Not only called from UFOpaedia but also from other places to display * @todo Don't display things like speed for base defence items - a missile * facility isn't getting slower or faster due a special weapon or ammunition */ void UP_AircraftItemDescription (const objDef_t* item) { static char itemText[1024]; const technology_t* tech; /* Set menu text node content to null. */ cgi->INV_ItemDescription(nullptr); *itemText = '\0'; /* no valid item id given */ if (!item) { cgi->Cvar_Set("mn_item", ""); cgi->Cvar_Set("mn_itemname", ""); cgi->Cvar_Set("mn_upmodel_top", ""); cgi->UI_ResetData(TEXT_ITEMDESCRIPTION); return; } tech = RS_GetTechForItem(item); /* select item */ cgi->Cvar_Set("mn_item", "%s", item->id); cgi->Cvar_Set("mn_itemname", "%s", _(item->name)); if (tech->mdl) cgi->Cvar_Set("mn_upmodel_top", "%s", tech->mdl); else cgi->Cvar_Set("mn_upmodel_top", ""); /* set description text */ if (RS_IsResearched_ptr(tech)) { const objDef_t* ammo = nullptr; switch (item->craftitem.type) { case AC_ITEM_WEAPON: Q_strcat(itemText, sizeof(itemText), _("Weight:\t%s\n"), AII_WeightToName(AII_GetItemWeightBySize(item))); break; case AC_ITEM_BASE_MISSILE: case AC_ITEM_BASE_LASER: Q_strcat(itemText, sizeof(itemText), _("Weapon for base defence system\n")); break; case AC_ITEM_AMMO: ammo = item; break; default: break; } /* check ammo of weapons */ if (item->craftitem.type <= AC_ITEM_WEAPON) { for(int i = 0; i < item->numAmmos; i++) if (item->ammos[i]->isVirtual) { ammo = item->ammos[i]; break; } } if (ammo) { /* We display the characteristics of this ammo */ Q_strcat(itemText, sizeof(itemText), _("Ammo:\t%i\n"), ammo->ammo); if (!EQUAL(ammo->craftitem.weaponDamage, 0)) Q_strcat(itemText, sizeof(itemText), _("Damage:\t%i\n"), (int) ammo->craftitem.weaponDamage); Q_strcat(itemText, sizeof(itemText), _("Reloading time:\t%i\n"), (int) ammo->craftitem.weaponDelay); } /* We write the range of the weapon */ if (!EQUAL(item->craftitem.stats[AIR_STATS_WRANGE], 0)) Q_strcat(itemText, sizeof(itemText), "%s:\t%i\n", UP_AircraftStatToName(AIR_STATS_WRANGE), AIR_AircraftMenuStatsValues(item->craftitem.stats[AIR_STATS_WRANGE], AIR_STATS_WRANGE)); /* we scan all stats except weapon range */ for (int i = 0; i < AIR_STATS_MAX; i++) { const char* statsName = UP_AircraftStatToName(i); if (i == AIR_STATS_WRANGE) continue; if (item->craftitem.stats[i] > 2.0f) Q_strcat(itemText, sizeof(itemText), "%s:\t+%i\n", statsName, AIR_AircraftMenuStatsValues(item->craftitem.stats[i], i)); else if (item->craftitem.stats[i] < -2.0f) Q_strcat(itemText, sizeof(itemText), "%s:\t%i\n", statsName, AIR_AircraftMenuStatsValues(item->craftitem.stats[i], i)); else if (item->craftitem.stats[i] > 1.0f) Q_strcat(itemText, sizeof(itemText), _("%s:\t+%i %%\n"), statsName, (int)(item->craftitem.stats[i] * 100) - 100); else if (!EQUAL(item->craftitem.stats[i], 0)) Q_strcat(itemText, sizeof(itemText), _("%s:\t%i %%\n"), statsName, (int)(item->craftitem.stats[i] * 100) - 100); } } else { Q_strcat(itemText, sizeof(itemText), _("Unknown - need to research this")); } cgi->Cvar_Set("mn_upmetadata", "1"); cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText); }