/** * @brief Prints the UFOpaedia description for buildings * @sa UP_Article */ static void UP_BuildingDescription (const technology_t* t) { const building_t* b = B_GetBuildingTemplate(t->provides); if (!b) { Com_sprintf(upBuffer, sizeof(upBuffer), _("Error - could not find building")); } else { Com_sprintf(upBuffer, sizeof(upBuffer), _("Needs:\t%s\n"), b->dependsBuilding ? _(b->dependsBuilding->name) : _("None")); Q_strcat(upBuffer, sizeof(upBuffer), ngettext("Construction time:\t%i day\n", "Construction time:\t%i days\n", b->buildTime), b->buildTime); Q_strcat(upBuffer, sizeof(upBuffer), _("Cost:\t%i c\n"), b->fixCosts); Q_strcat(upBuffer, sizeof(upBuffer), _("Running costs:\t%i c\n"), b->varCosts); } cgi->Cvar_Set("mn_upmetadata", "1"); cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, upBuffer); UP_DisplayTechTree(t); }
/** * @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 Checks why a button in base menu is disabled, and create a popup to inform player */ static void B_CheckBuildingStatusForMenu_f (void) { int num; const char *buildingID; const building_t *building; const base_t *base = B_GetCurrentSelectedBase(); if (cgi->Cmd_Argc() != 2) { Com_Printf("Usage: %s <buildingID>\n", cgi->Cmd_Argv(0)); return; } buildingID = cgi->Cmd_Argv(1); building = B_GetBuildingTemplate(buildingID); if (!building || !base) return; /* Maybe base is under attack ? */ if (B_IsUnderAttack(base)) { CP_Popup(_("Notice"), _("Base is under attack, you can't access this building !")); return; } if (building->buildingType == B_HANGAR) { /* this is an exception because you must have a small or large hangar to enter aircraft menu */ CP_Popup(_("Notice"), _("You need at least one Hangar (and its dependencies) to use aircraft.")); return; } num = B_GetNumberOfBuildingsInBaseByBuildingType(base, building->buildingType); if (num > 0) { int numUnderConstruction; /* maybe all buildings of this type are under construction ? */ B_CheckBuildingTypeStatus(base, building->buildingType, B_STATUS_UNDER_CONSTRUCTION, &numUnderConstruction); if (numUnderConstruction == num) { int minDay = 99999; building_t *b = NULL; while ((b = B_GetNextBuildingByType(base, b, building->buildingType))) { if (b->buildingStatus == B_STATUS_UNDER_CONSTRUCTION) { const float remaining = B_GetConstructionTimeRemain(b); minDay = std::min(minDay, (int)std::max(0.0f, remaining)); } } CP_Popup(_("Notice"), ngettext("Construction of building will be over in %i day.\nPlease wait to enter.", "Construction of building will be over in %i days.\nPlease wait to enter.", minDay), minDay); return; } if (!B_CheckBuildingDependencesStatus(building)) { const building_t *dependenceBuilding = building->dependsBuilding; assert(building->dependsBuilding); if (B_GetNumberOfBuildingsInBaseByBuildingType(base, dependenceBuilding->buildingType) <= 0) { /* the dependence of the building is not built */ CP_Popup(_("Notice"), _("You need a building %s to make building %s functional."), _(dependenceBuilding->name), _(building->name)); return; } else { /* maybe the dependence of the building is under construction * note that we can't use B_STATUS_UNDER_CONSTRUCTION here, because this value * is not use for every building (for exemple Command Centre) */ building_t *b = NULL; while ((b = B_GetNextBuildingByType(base, b, dependenceBuilding->buildingType))) { if (!B_IsBuildingBuiltUp(b)) { CP_Popup(_("Notice"), _("Building %s is not finished yet, and is needed to use building %s."), _(dependenceBuilding->name), _(building->name)); return; } } /* the dependence is built but doesn't work - must be because of their dependendes */ CP_Popup(_("Notice"), _("Make sure that the dependencies of building %s (%s) are operational, so that building %s may be used."), _(dependenceBuilding->name), _(dependenceBuilding->dependsBuilding->name), _(building->name)); return; } } /* all buildings are OK: employees must be missing */ if (building->buildingType == B_WORKSHOP && E_CountHired(base, EMPL_WORKER) <= 0) { CP_Popup(_("Notice"), _("You need to recruit %s to use building %s."), E_GetEmployeeString(EMPL_WORKER, 2), _(building->name)); return; } else if (building->buildingType == B_LAB && E_CountHired(base, EMPL_SCIENTIST) <= 0) { CP_Popup(_("Notice"), _("You need to recruit %s to use building %s."), E_GetEmployeeString(EMPL_SCIENTIST, 2), _(building->name)); return; } } else { CP_Popup(_("Notice"), _("Build a %s first."), _(building->name)); return; } }