/** * @brief Run actions on finishing production of one item/aircraft/UGV.. * @param base The base to produce in * @param prod The production that is running */ static void PR_FinishProduction (base_t* base, production_t* prod) { const char* name = PR_GetName(&prod->data); technology_t* tech = PR_GetTech(&prod->data); prod->frame = 0; prod->amount--; if (PR_IsItem(prod)) { CP_UpdateCredits(ccs.credits - PR_GetPrice(prod->data.data.item)); /* Now add it to equipment and update capacity. */ B_AddToStorage(base, prod->data.data.item, 1); } else if (PR_IsAircraft(prod)) { CP_UpdateCredits(ccs.credits - PR_GetPrice(prod->data.data.aircraft)); /* Now add new aircraft. */ AIR_NewAircraft(base, prod->data.data.aircraft); } if (prod->amount > 0) return; Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Work on %s at %s has finished."), name, base->name); MSO_CheckAddNewMessage(NT_PRODUCTION_FINISHED, _("Production finished"), cp_messageBuffer, MSG_PRODUCTION, tech); /* queue the next production */ PR_QueueNext(base); }
/** * @brief Base Summary menu init function. * @note Should be called whenever the Base Summary menu gets active. */ static void BaseSummary_Init (const base_t *base) { static char textStatsBuffer[1024]; static char textInfoBuffer[256]; const aliensCont_t *containment = base->alienscont; int i; baseCapacities_t cap; const production_queue_t *queue; const technology_t *tech; int tmp; /* wipe away old buffers */ textStatsBuffer[0] = textInfoBuffer[0] = 0; Q_strcat(textInfoBuffer, _("^BAircraft\n"), sizeof(textInfoBuffer)); for (i = 0; i <= MAX_HUMAN_AIRCRAFT_TYPE; i++) { const aircraftType_t airType = (aircraftType_t)i; const int count = AIR_CountTypeInBase(base, airType); if (count == 0) continue; Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i\n", AIR_GetAircraftString(airType), count), sizeof(textInfoBuffer)); } Q_strcat(textInfoBuffer, "\n", sizeof(textInfoBuffer)); Q_strcat(textInfoBuffer, _("^BEmployees\n"), sizeof(textInfoBuffer)); for (i = 0; i < MAX_EMPL; i++) { const employeeType_t emplType = (employeeType_t)i; tmp = E_CountHired(base, emplType); if (tmp == 0) continue; Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i\n", E_GetEmployeeString(emplType, tmp), tmp), sizeof(textInfoBuffer)); } Q_strcat(textInfoBuffer, "\n", sizeof(textInfoBuffer)); Q_strcat(textInfoBuffer, _("^BAliens\n"), sizeof(textInfoBuffer)); for (i = 0; i < ccs.numAliensTD; i++) { if (!containment[i].amountAlive && !containment[i].amountDead) continue; Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i/%i\n", _(containment[i].teamDef->name), containment[i].amountAlive, containment[i].amountDead), sizeof(textInfoBuffer)); } /* link into the menu */ cgi->UI_RegisterText(TEXT_STANDARD, textInfoBuffer); Q_strcat(textStatsBuffer, _("^BBuildings\t\t\t\t\t\tCapacity\t\t\t\tAmount\n"), sizeof(textStatsBuffer)); for (i = 0; i < ccs.numBuildingTemplates; i++) { const building_t* b = &ccs.buildingTemplates[i]; /* only show already researched buildings */ if (!RS_IsResearched_ptr(b->tech)) continue; cap = B_GetCapacityFromBuildingType(b->buildingType); if (cap == MAX_CAP) continue; if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, b->buildingType)) continue; /* Check if building is functional (see comments in B_UpdateBaseCapacities) */ if (B_GetBuildingStatus(base, b->buildingType)) { Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%i/%i", _(b->name), CAP_GetCurrent(base, cap), CAP_GetMax(base, cap)), sizeof(textStatsBuffer)); } else { if (b->buildingStatus == B_STATUS_UNDER_CONSTRUCTION) { const float remaining = B_GetConstructionTimeRemain(b); const float timeLeft = std::max(0.0f, remaining); Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%3.1f %s", _(b->name), timeLeft, ngettext("day", "days", timeLeft)), sizeof(textStatsBuffer)); } else { Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%i/%i", _(b->name), CAP_GetCurrent(base, cap), 0), sizeof(textStatsBuffer)); } } Q_strcat(textStatsBuffer, va("\t\t\t\t%i\n", B_GetNumberOfBuildingsInBaseByBuildingType(base, b->buildingType)), sizeof(textStatsBuffer)); } Q_strcat(textStatsBuffer, "\n", sizeof(textStatsBuffer)); Q_strcat(textStatsBuffer, _("^BProduction\t\t\t\t\t\tQuantity\t\t\t\tPercent\n"), sizeof(textStatsBuffer)); queue = PR_GetProductionForBase(base); if (queue->numItems > 0) { for (i = 0; i < queue->numItems; i++) { const production_t *production = &queue->items[i]; const char *name = PR_GetName(&production->data); /** @todo use the same method as we do in PR_ProductionInfo */ Q_strcat(textStatsBuffer, va(_("%s\t\t\t\t\t\t%d\t\t\t\t%.2f%%\n"), name, production->amount, PR_GetProgress(production) * 100), sizeof(textStatsBuffer)); } } else { Q_strcat(textStatsBuffer, _("Nothing\n"), sizeof(textStatsBuffer)); } Q_strcat(textStatsBuffer, "\n", sizeof(textStatsBuffer)); Q_strcat(textStatsBuffer, _("^BResearch\t\t\t\t\t\tScientists\t\t\t\tPercent\n"), sizeof(textStatsBuffer)); tmp = 0; for (i = 0; i < ccs.numTechnologies; i++) { tech = RS_GetTechByIDX(i); if (tech->base == base && (tech->statusResearch == RS_RUNNING || tech->statusResearch == RS_PAUSED)) { Q_strcat(textStatsBuffer, va(_("%s\t\t\t\t\t\t%d\t\t\t\t%1.2f%%\n"), _(tech->name), tech->scientists, (1 - tech->time / tech->overallTime) * 100), sizeof(textStatsBuffer)); tmp++; } } if (!tmp) Q_strcat(textStatsBuffer, _("Nothing\n"), sizeof(textStatsBuffer)); /* link into the menu */ cgi->UI_RegisterText(TEXT_STATS_BASESUMMARY, textStatsBuffer); }
/** * @brief Initialises base. * @note This command is executed in the init node of the base menu. * It is called everytime the base menu pops up and sets the cvars. * @todo integrate building status tooltips from B_CheckBuildingStatusForMenu_f into this one */ static void B_BaseInit_f (void) { int i; base_t *base = B_GetCurrentSelectedBase(); if (!base) return; /* make sure the credits cvar is up-to-date */ CP_UpdateCredits(ccs.credits); cgi->Cvar_SetValue("mn_base_num_aircraft", AIR_BaseCountAircraft(base)); /* activate or deactivate the aircraft button */ if (AIR_AircraftAllowed(base)) { if (AIR_BaseHasAircraft(base)) cgi->UI_ExecuteConfunc("update_basebutton aircraft false \"%s\"", _("Aircraft management and crew equipment")); else cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("Buy or produce at least one aircraft first.")); } else { cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("No Hangar functional in base.")); } if (BS_BuySellAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton buysell false \"%s\"", _("Buy/Sell equipment, aircraft and UGV")); else cgi->UI_ExecuteConfunc("update_basebutton buysell true \"%s\"", va(_("No %s functional in base."), _("Storage"))); if (B_GetCount() > 1) cgi->UI_ExecuteConfunc("update_basebutton transfer false \"%s\"", _("Transfer equipment, vehicles, aliens and employees to other bases")); else cgi->UI_ExecuteConfunc("update_basebutton transfer true \"%s\"", _("Build at least a second base to transfer equipment or personnel")); if (RS_ResearchAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton research false \"%s\"", _("Research new technology")); else cgi->UI_ExecuteConfunc("update_basebutton research true \"%s\"", va(_("No %s functional in base."), _("Laboratory"))); if (PR_ProductionAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton production false \"%s\"", _("Produce equipment, aircraft and UGV")); else cgi->UI_ExecuteConfunc("update_basebutton production true \"%s\"", va(_("No %s functional in base."), _("Workshop"))); if (E_HireAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton hire false \"%s\"", _("Hire or dismiss employees")); else cgi->UI_ExecuteConfunc("update_basebutton hire true \"%s\"", va(_("No %s functional in base."), _("Living Quarters"))); if (AC_ContainmentAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton containment false \"%s\"", _("Manage captured aliens")); else cgi->UI_ExecuteConfunc("update_basebutton containment true \"%s\"", va(_("No %s functional in base."), _("Containment"))); if (HOS_HospitalAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton hospital false \"%s\"", _("Treat wounded soldiers and perform implant surgery")); else cgi->UI_ExecuteConfunc("update_basebutton hospital true \"%s\"", va(_("No %s functional in base."), _("Hospital"))); /* * Gather data on current/max space for living quarters, storage, lab and workshop * clear_bld_space ensures 0/0 data for facilities which may not exist in base */ cgi->UI_ExecuteConfunc("clear_bld_space"); for (i = 0; i < ccs.numBuildingTemplates; i++) { const building_t* b = &ccs.buildingTemplates[i]; const baseCapacities_t capType = B_GetCapacityFromBuildingType(b->buildingType); capacities_t cap; if (capType == MAX_CAP) continue; /* Check if building matches one of our four types */ if (b->buildingType != B_QUARTERS && b->buildingType != B_STORAGE && b->buildingType != B_WORKSHOP && b->buildingType != B_LAB && b->buildingType != B_ANTIMATTER) continue; /* only show already researched buildings */ if (!RS_IsResearched_ptr(b->tech)) continue; cap = *CAP_Get(base, capType); assert(b->tpl); const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl); if (count < 1) continue; cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount); } /* * Get the number of different employees in the base * @todo: Get the number of injured soldiers if hospital exists */ cgi->UI_ExecuteConfunc("current_employees %i %i %i %i", E_CountHired(base, EMPL_SOLDIER), E_CountHired(base, EMPL_PILOT), E_CountHired(base, EMPL_SCIENTIST), E_CountHired(base, EMPL_WORKER)); /* * List the first five aircraft in the base if they exist */ cgi->UI_ExecuteConfunc("clear_aircraft"); if (AIR_AircraftAllowed(base)) { if (AIR_BaseHasAircraft(base)) { i = 0; AIR_ForeachFromBase(aircraft, base) { if (i > 5) break; /* * UI node should use global IDX to identify aircraft but it uses order of aircraft in base (i) * See @todo in cp_aircraft_callbacks.c in AIR_AircraftSelect() */ cgi->UI_ExecuteConfunc("show_aircraft %i \"%s\" \"%s\" \"%s\" %i", i, aircraft->name, aircraft->id, AIR_AircraftStatusToName(aircraft), AIR_IsAircraftInBase(aircraft)); i++; } } } /* Get the research item closest to completion in the base if it exists */ cgi->UI_ExecuteConfunc("clear_research"); if (RS_ResearchAllowed(base)) { const technology_t *closestTech = NULL; double finished = -1; for (i = 0; i < ccs.numTechnologies; i++) { const technology_t *tech = RS_GetTechByIDX(i); if (!tech) continue; if (tech->base != base) continue; if (tech->statusResearch == RS_RUNNING) { const double percent = (1 - tech->time / tech->overallTime) * 100; if (percent > finished) { finished = percent; closestTech = tech; } } } if (closestTech != NULL) cgi->UI_ExecuteConfunc("show_research \"%s\" %i %3.0f", closestTech->name, closestTech->scientists, finished); } /* Get the production item closest to completion in the base if it exists */ cgi->UI_ExecuteConfunc("clear_production"); if (PR_ProductionAllowed(base)) { const production_queue_t *queue = PR_GetProductionForBase(base); if (queue->numItems > 0) { const production_t *production = &queue->items[0]; cgi->UI_ExecuteConfunc("show_production \"%s\" %3.0f", PR_GetName(&production->data), PR_GetProgress(production) * 100); } } }