/**
 * @brief Set AIM_selectedTechnology to the technology of current selected aircraft item.
 * @sa AIM_AircraftEquipMenuUpdate_f
 */
static void AIM_AircraftEquipMenuClick_f (void)
{
	int techIdx;

	if (Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <num>\n", Cmd_Argv(0));
		return;
	}

	/* Which tech? */
	techIdx = atoi(Cmd_Argv(1));
	aimSelectedTechnology = RS_GetTechByIDX(techIdx);
	AIM_UpdateItemDescription(true, false);
}
Ejemplo n.º 2
0
/**
 * @brief Fills technology list on research UI
 */
static void RS_FillTechnologyList_f (void)
{
	base_t* base = B_GetCurrentSelectedBase();

	if (!base)
		return;

	RS_MarkResearchable(base);

	cgi->UI_ExecuteConfunc("ui_research_update_caps %d %d %d %d", E_CountUnassigned(base, EMPL_SCIENTIST),
		E_CountHired(base, EMPL_SCIENTIST), CAP_GetFreeCapacity(base, CAP_LABSPACE), CAP_GetMax(base, CAP_LABSPACE));
	cgi->UI_ExecuteConfunc("ui_techlist_clear");
	for (int i = 0; i < ccs.numTechnologies; i++) {
		technology_t* tech = RS_GetTechByIDX(i);
		/* Don't show technologies with time == 0 - those are NOT separate research topics. */
		if (tech->time == 0)
			continue;
		/* hide finished research */
		if (tech->statusResearch == RS_FINISH)
			continue;

		int percentage = 0;
		if (tech->overallTime > 0.0) {
			percentage = std::min(100, std::max(0, 100 - int(round(tech->time * 100.0 / tech->overallTime))));
		}

		/* show researches that are running */
		if (tech->base && tech->scientists > 0) {
			if (tech->base == base) {
				cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d", tech->id, _(tech->name), tech->scientists, percentage);
			} else {
				cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d base %d \"%s\"", tech->id, _(tech->name), tech->scientists,
					percentage, tech->base->idx, tech->base->name);
			}
			continue;
		}
		/* show topics that are researchable on this base */
		const bool req = RS_RequirementsMet(tech, base);
		if (tech->statusResearchable && req) {
			cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d", tech->id, _(tech->name), tech->scientists, percentage);
			continue;
		}
		if (tech->statusCollected && !req) {
			cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d missing", tech->id, _(tech->name), tech->scientists, percentage);
			continue;
		}
	}
}
Ejemplo n.º 3
0
/**
 * @brief This function parses a list of items that should be set to researchable = true after campaign start
 * @param[in] campaign The campaign data structure
 * @param[in] name Name of the techlist
 * @param[in,out] text Script to parse
 * @param[in] researchable Mark them researchable or not researchable
 * @sa CP_ParseScriptFirst
 */
static void CP_ParseResearchableCampaignStates (const campaign_t *campaign, const char *name, const char **text, qboolean researchable)
{
	const char *errhead = "CP_ParseResearchableCampaignStates: unexpected end of file (equipment ";
	const char *token;
	int i;

	/* get it's body */
	token = Com_Parse(text);

	if (!*text || *token != '{') {
		Com_Printf("CP_ParseResearchableCampaignStates: equipment def \"%s\" without body ignored\n", name);
		return;
	}

	if (!Q_streq(campaign->researched, name)) {
		Com_DPrintf(DEBUG_CLIENT, "..don't use '%s' as researchable list\n", name);
		return;
	}

	Com_DPrintf(DEBUG_CLIENT, "..campaign researchable list '%s'\n", name);
	do {
		token = Com_EParse(text, errhead, name);
		if (!*text || *token == '}')
			return;

		for (i = 0; i < ccs.numTechnologies; i++) {
			technology_t *tech = RS_GetTechByIDX(i);
			if (Q_streq(token, tech->id)) {
				if (researchable) {
					tech->mailSent = MAILSENT_PROPOSAL;
					RS_MarkOneResearchable(tech);
				} else {
					/** @todo Mark unresearchable */
				}
				Com_DPrintf(DEBUG_CLIENT, "...tech %s\n", tech->id);
				break;
			}
		}

		if (i == ccs.numTechnologies)
			Com_Printf("CP_ParseResearchableCampaignStates: unknown token \"%s\" ignored (tech %s)\n", token, name);

	} while (*text);
}
Ejemplo n.º 4
0
/**
 * @brief This function parses a list of items that should be set to researched = true after campaign start
 */
static void CP_ParseResearchedCampaignItems (const campaign_t *campaign, const char *name, const char **text)
{
	const char *errhead = "CP_ParseResearchedCampaignItems: unexpected end of file (equipment ";
	const char *token;
	int i;

	/* Don't parse if it is not definition for current type of campaign. */
	if (!Q_streq(campaign->researched, name))
		return;

	/* get it's body */
	token = Com_Parse(text);

	if (!*text || *token != '{') {
		Com_Printf("CP_ParseResearchedCampaignItems: equipment def \"%s\" without body ignored (%s)\n",
				name, token);
		return;
	}

	Com_DPrintf(DEBUG_CLIENT, "..campaign research list '%s'\n", name);
	do {
		token = Com_EParse(text, errhead, name);
		if (!*text || *token == '}')
			return;

		for (i = 0; i < ccs.numTechnologies; i++) {
			technology_t *tech = RS_GetTechByIDX(i);
			assert(tech);
			if (Q_streq(token, tech->id)) {
				tech->mailSent = MAILSENT_FINISHED;
				tech->markResearched.markOnly[tech->markResearched.numDefinitions] = qtrue;
				tech->markResearched.campaign[tech->markResearched.numDefinitions] = Mem_PoolStrDup(name, cp_campaignPool, 0);
				tech->markResearched.numDefinitions++;
				Com_DPrintf(DEBUG_CLIENT, "...tech %s\n", tech->id);
				break;
			}
		}

		if (i == ccs.numTechnologies)
			Com_Printf("CP_ParseResearchedCampaignItems: unknown token \"%s\" ignored (tech %s)\n", token, name);

	} while (*text);
}
Ejemplo n.º 5
0
/**
 * @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);
}
Ejemplo n.º 6
0
/**
 * @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);
		}
	}
}