/** * @brief Prints the description for robots/ugvs. * @param[in] ugvType What type of robot/ugv to print the description for. * @sa BS_MarketClick_f * @sa UP_Article */ void UP_UGVDescription (const ugv_t* ugvType) { static char itemText[512]; const technology_t* tech; assert(ugvType); tech = RS_GetTechByProvided(ugvType->id); assert(tech); cgi->INV_ItemDescription(nullptr); /* Set name of ugv/robot */ cgi->Cvar_Set("mn_itemname", "%s", _(tech->name)); cgi->Cvar_Set("mn_item", "%s", tech->provides); cgi->Cvar_Set("mn_upmetadata", "1"); if (RS_IsResearched_ptr(tech)) { /** @todo make me shiny */ Com_sprintf(itemText, sizeof(itemText), _("%s\n%s"), _(tech->name), ugvType->weapon); } else if (RS_Collected_(tech)) { /** @todo Display crippled info and pre-research text here */ Com_sprintf(itemText, sizeof(itemText), _("Unknown - need to research this")); } else { Com_sprintf(itemText, sizeof(itemText), _("Unknown - need to research this")); } cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText); }
/** * @brief Opens the UFOpedia for the current selected item/aircraft. * @note called by market_openpedia */ static void BS_MarketInfoClick_f (void) { const technology_t *tech = RS_GetTechByProvided(Cvar_GetString("mn_item")); if (tech) UP_OpenWith(tech->id); }
/** * @brief Load callback for savegames in XML Format * @param[in] parent XML Node structure, where we get the information from */ bool AIRFIGHT_LoadXML (xmlNode_t* parent) { int i; xmlNode_t* node; for (i = 0, node = cgi->XML_GetNode(parent, SAVE_AIRFIGHT_PROJECTILE); i < MAX_PROJECTILESONGEOSCAPE && node; node = cgi->XML_GetNextNode(node, parent, SAVE_AIRFIGHT_PROJECTILE), i++) { technology_t* tech = RS_GetTechByProvided(cgi->XML_GetString(node, SAVE_AIRFIGHT_ITEMID)); int j; xmlNode_t* positions; xmlNode_t* attackingAircraft; xmlNode_t* aimedAircraft; aircraftProjectile_t* projectile = &ccs.projectiles[i]; if (!tech) { Com_Printf("AIR_Load: Could not get technology of projectile %i\n", i); return false; } projectile->aircraftItem = INVSH_GetItemByID(tech->provides); for (j = 0, positions = cgi->XML_GetPos2(node, SAVE_AIRFIGHT_POS, projectile->pos[0]); j < MAX_MULTIPLE_PROJECTILES && positions; j++, positions = cgi->XML_GetNextPos2(positions, node, SAVE_AIRFIGHT_POS, projectile->pos[j])) ; projectile->numProjectiles = j; cgi->XML_GetPos3(node, SAVE_AIRFIGHT_IDLETARGET, projectile->idleTarget); projectile->time = cgi->XML_GetInt(node, SAVE_AIRFIGHT_TIME, 0); projectile->angle = cgi->XML_GetFloat(node, SAVE_AIRFIGHT_ANGLE, 0.0); projectile->bullets = cgi->XML_GetBool(node, SAVE_AIRFIGHT_BULLET, false); projectile->beam = cgi->XML_GetBool(node, SAVE_AIRFIGHT_BEAM, false); if ((attackingAircraft = cgi->XML_GetNode(node, SAVE_AIRFIGHT_ATTACKINGAIRCRAFT))) { if (cgi->XML_GetBool(attackingAircraft, SAVE_AIRFIGHT_ISUFO, false)) /** @todo 0 as default might be incorrect */ projectile->attackingAircraft = UFO_GetByIDX(cgi->XML_GetInt(attackingAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, 0)); else projectile->attackingAircraft = AIR_AircraftGetFromIDX(cgi->XML_GetInt(attackingAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, AIRCRAFT_INVALID)); } else { projectile->attackingAircraft = nullptr; } cgi->XML_GetPos3(node, SAVE_AIRFIGHT_ATTACKERPOS, projectile->attackerPos); if ((aimedAircraft = cgi->XML_GetNode(node, SAVE_AIRFIGHT_AIMEDAIRCRAFT))) { if (cgi->XML_GetBool(aimedAircraft, SAVE_AIRFIGHT_ISUFO, false)) /** @todo 0 as default might be incorrect */ projectile->aimedAircraft = UFO_GetByIDX(cgi->XML_GetInt(aimedAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, 0)); else projectile->aimedAircraft = AIR_AircraftGetFromIDX(cgi->XML_GetInt(aimedAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, AIRCRAFT_INVALID)); } else { projectile->aimedAircraft = nullptr; } } ccs.numProjectiles = i; return true; }
/** * @brief Copies an entry from the building description file into the list of building types. * @note Parses one "building" entry in the basemanagement.ufo file and writes * it into the next free entry in bmBuildings[0], which is the list of buildings * in the first base (building_t). * @param[in] name Unique script id of a building. This is parsed from "building xxx" -> id=xxx. * @param[in] text the whole following text that is part of the "building" item definition in .ufo. * @param[in] link Bool value that decides whether to link the tech pointer in or not * @sa CL_ParseScriptFirst (link is false here) * @sa CL_ParseScriptSecond (link it true here) */ void B_ParseBuildings (const char *name, const char **text, bool link) { building_t *building; technology_t *techLink; const char *errhead = "B_ParseBuildings: unexpected end of file (names "; const char *token; /* get id list body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("B_ParseBuildings: building \"%s\" without body ignored\n", name); return; } if (ccs.numBuildingTemplates >= MAX_BUILDINGS) cgi->Com_Error(ERR_DROP, "B_ParseBuildings: too many buildings"); if (!link) { int i; for (i = 0; i < ccs.numBuildingTemplates; i++) { if (Q_streq(ccs.buildingTemplates[i].id, name)) { Com_Printf("B_ParseBuildings: Second building with same name found (%s) - second ignored\n", name); return; } } /* new entry */ building = &ccs.buildingTemplates[ccs.numBuildingTemplates]; OBJZERO(*building); building->id = Mem_PoolStrDup(name, cp_campaignPool, 0); Com_DPrintf(DEBUG_CLIENT, "...found building %s\n", building->id); /* set standard values */ building->tpl = building; /* Self-link just in case ... this way we can check if it is a template or not. */ building->idx = -1; /* No entry in buildings list (yet). */ building->base = NULL; building->buildingType = MAX_BUILDING_TYPE; building->dependsBuilding = NULL; building->maxCount = -1; /* Default: no limit */ building->size[0] = 1; building->size[1] = 1; ccs.numBuildingTemplates++; do { /* get the name type */ token = cgi->Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* get values */ if (Q_streq(token, "type")) { token = cgi->Com_EParse(text, errhead, name); if (!*text) return; building->buildingType = B_GetBuildingTypeByBuildingID(token); if (building->buildingType >= MAX_BUILDING_TYPE) Com_Printf("didn't find buildingType '%s'\n", token); } else { /* no linking yet */ if (Q_streq(token, "depends")) { cgi->Com_EParse(text, errhead, name); if (!*text) return; } else { if (!Com_ParseBlockToken(name, text, building, valid_building_vars, cp_campaignPool, token)) Com_Printf("B_ParseBuildings: unknown token \"%s\" ignored (building %s)\n", token, name); } } } while (*text); if (building->size[0] < 1 || building->size[1] < 1 || building->size[0] >= BASE_SIZE || building->size[1] >= BASE_SIZE) { Com_Printf("B_ParseBuildings: Invalid size for building %s (%i, %i)\n", building->id, (int)building->size[0], (int)building->size[1]); ccs.numBuildingTemplates--; } } else { building = B_GetBuildingTemplate(name); if (!building) cgi->Com_Error(ERR_DROP, "B_ParseBuildings: Could not find building with id %s\n", name); techLink = RS_GetTechByProvided(name); if (techLink) building->tech = techLink; do { /* get the name type */ token = cgi->Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* get values */ if (Q_streq(token, "depends")) { const building_t *dependsBuilding = B_GetBuildingTemplate(cgi->Com_EParse(text, errhead, name)); if (!dependsBuilding) cgi->Com_Error(ERR_DROP, "Could not find building depend of %s\n", building->id); building->dependsBuilding = dependsBuilding; if (!*text) return; } } while (*text); } }
/** * @brief Fill market item list */ static void BS_FillMarket_f (void) { const base_t* base = B_GetCurrentSelectedBase(); itemFilterTypes_t type; if (cgi->Cmd_Argc() < 2) { cgi->Com_Printf("Usage: %s <category>\n", cgi->Cmd_Argv(0)); return; } if (cgi->Cmd_Argc() >= 3) base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(2))); if (!base) { cgi->Com_Printf("No/invalid base selected.\n"); return; } type = cgi->INV_GetFilterTypeID(cgi->Cmd_Argv(1)); cgi->UI_ExecuteConfunc("ui_market_clear"); switch (type) { case FILTER_UGVITEM: /* show own UGV */ E_Foreach(EMPL_ROBOT, robot) { const ugv_t* ugv = robot->getUGV(); const technology_t* tech = RS_GetTechByProvided(ugv->id); if (!robot->isHiredInBase(base)) continue; cgi->UI_ExecuteConfunc("ui_market_add \"ugv-%d\" \"%s\" 1 0 0 %d - \"%s\"", robot->chr.ucn, _(tech->name), ugv->price, robot->isAwayFromBase() ? _("UGV is away from home") : "-"); } /* show buyable UGV */ for (int i = 0; i < cgi->csi->numUGV; i++) { const ugv_t* ugv = &cgi->csi->ugvs[i]; const technology_t* tech = RS_GetTechByProvided(ugv->id); const objDef_t* ugvWeapon = INVSH_GetItemByID(ugv->weapon); const int buyable = std::min(E_CountUnhiredRobotsByType(ugv), BS_GetItemOnMarket(ugvWeapon)); assert(tech); if (!RS_IsResearched_ptr(tech)) continue; if (buyable <= 0) continue; cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" 0 %d %d %d - -", ugv->id, _(tech->name), buyable, ugv->price, ugv->price); } /* show (UGV) items, fall through */ case FILTER_S_PRIMARY: case FILTER_S_SECONDARY: case FILTER_S_HEAVY: case FILTER_S_IMPLANT: case FILTER_S_MISC: case FILTER_S_ARMOUR: case FILTER_DUMMY: case FILTER_CRAFTITEM: case MAX_FILTERTYPES: { for (int i = 0; i < cgi->csi->numODs; i++) { const objDef_t* od = &cgi->csi->ods[i]; const technology_t* tech = RS_GetTechForItem(od); if (!BS_IsOnMarket(od)) continue; if (B_ItemInBase(od, base) + BS_GetItemOnMarket(od) <= 0) continue; if (type != MAX_FILTERTYPES && !cgi->INV_ItemMatchesFilter(od, type)) continue; cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" %d %d %d %d %s -", od->id, _(od->name), B_ItemInBase(od, base), BS_GetItemOnMarket(od), BS_GetItemBuyingPrice(od), BS_GetItemSellingPrice(od), RS_IsResearched_ptr(tech) ? va("%d", ccs.eMarket.autosell[i]) : "-"); } break; } case FILTER_AIRCRAFT: { AIR_ForeachFromBase(aircraft, base) { cgi->UI_ExecuteConfunc("ui_market_add \"aircraft_%d\" \"%s\" 1 0 0 %d - \"%s\"", aircraft->idx, aircraft->name, BS_GetAircraftSellingPrice(aircraft), AIR_IsAircraftInBase(aircraft) ? "-" : _("Aircraft is away from home")); } for (int i = 0; i < ccs.numAircraftTemplates; i++) { const aircraft_t* aircraft = &ccs.aircraftTemplates[i]; if (!BS_AircraftIsOnMarket(aircraft)) continue; if (!RS_IsResearched_ptr(aircraft->tech)) continue; if (BS_GetAircraftOnMarket(aircraft) <= 0) continue; cgi->UI_ExecuteConfunc("ui_market_add \"%s\" \"%s\" 0 %d %d %d - -", aircraft->id, _(aircraft->tech->name), BS_GetAircraftOnMarket(aircraft), BS_GetAircraftBuyingPrice(aircraft), BS_GetAircraftSellingPrice(aircraft)); } break; } default: break; }
/** * @brief Get the technology for a given UFO type * @param type UFO type to get the technology for * @return The technology for the given UFO. If no technology was found for the UFO * id this might return @c NULL. */ const technology_t* UFO_GetTechnologyFromType (const ufoType_t type) { const char *id = Com_UFOTypeToShortName(type); const technology_t *tech = RS_GetTechByProvided(id); return tech; }