Пример #1
0
/**
 * @brief Checks if the production requirements are met for a defined amount.
 * @param[in] amount How many items are planned to be produced.
 * @param[in] reqs The production requirements of the item that is to be produced.
 * @param[in] base Pointer to base.
 * @return how much item/aircraft/etc can be produced
 */
int PR_RequirementsMet (int amount, const requirements_t* reqs, base_t* base)
{
	int producibleAmount = amount;

	for (int i = 0; i < reqs->numLinks; i++) {
		const requirement_t* req = &reqs->links[i];

		switch (req->type) {
		case RS_LINK_ITEM: {
				const int items = std::min(amount, B_ItemInBase(req->link.od, base) / ((req->amount) ? req->amount : 1));
				producibleAmount = std::min(producibleAmount, items);
				break;
			}
		case RS_LINK_ANTIMATTER: {
				const int am = std::min(amount, B_AntimatterInBase(base) / ((req->amount) ? req->amount : 1));
				producibleAmount = std::min(producibleAmount, am);
				break;
			}
		case RS_LINK_TECH:
			producibleAmount = (RS_IsResearched_ptr(req->link.tech)) ? producibleAmount : 0;
			break;
		case RS_LINK_TECH_NOT:
			producibleAmount = (RS_IsResearched_ptr(req->link.tech)) ? 0 : producibleAmount;
			break;
		default:
			break;
		}
	}

	return producibleAmount;
}
Пример #2
0
/**
 * @brief Returns names of the UFO is UFO has been researched.
 * @param[in] ufocraft Pointer to the UFO.
 */
const char* UFO_AircraftToIDOnGeoscape (const aircraft_t *ufocraft)
{
	const technology_t *tech = ufocraft->tech;

	assert(tech);

	if (ufocraft->detectionIdx)
		return va("%s #%i", (RS_IsResearched_ptr(tech)) ? _(ufocraft->name) : _("UFO"), ufocraft->detectionIdx);
	return (RS_IsResearched_ptr(tech)) ? _(ufocraft->name) : _("UFO");
}
Пример #3
0
/**
 * @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);
}
/**
 * @return @c true if the technology is available and matches the filter
 */
static bool AIM_CrafttypeFilter (const base_t *base, aircraftItemType_t filterType, const technology_t *tech)
{
	const objDef_t *item;
	if (!base)
		return false;

	if (!RS_IsResearched_ptr(tech))
		return false;

	item = INVSH_GetItemByID(tech->provides);
	if (!item)
		return false;
	if (item->isVirtual)
		return false;
	if (!B_BaseHasItem(base, item))
		return false;

	/* filter by type: special case for ammo because more than 1 type is an ammo type */
	if (filterType != AC_ITEM_AMMO) {
		if (item->craftitem.type != filterType)
			return false;
	} else {
		if (item->craftitem.type < AC_ITEM_AMMO)
			return false;
	}

	/* 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 && filterType >= AC_ITEM_AMMO)
		return false;

	return true;
}
Пример #5
0
/**
 * @brief Update the display of building space for all researched facilities
 * @sa B_BaseInit_f
 */
static void B_BuildingSpace_f (void)
{
	int i;
	base_t *base = B_GetCurrentSelectedBase();

	if (!base)
		return;

	// Clear existing entries from the UI panel
	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;

		/* skip mandatory buildings (like Entrance) which are built automatically */
		if (b->mandatory)
			continue;
		/* only show already researched buildings */
		if (!RS_IsResearched_ptr(b->tech))
			continue;

		if (capType != MAX_CAP)
			cap = *CAP_Get(base, capType);
		else
			OBJZERO(cap);

		assert(b->tpl);
		const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl);

		cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount);
	}
}
Пример #6
0
/**
 * @brief Update the building-list.
 * @sa B_BuildingInit_f
 */
static void B_BuildingInit (base_t* base)
{
	int i;
	linkedList_t *buildingList = NULL;

	/* maybe someone call this command before the bases are parsed?? */
	if (!base)
		return;

	for (i = 0; i < ccs.numBuildingTemplates; i++) {
		building_t *tpl = &ccs.buildingTemplates[i];
		/* make an entry in list for this building */

		if (tpl->mapPart) {
			const int numSameBuildings = B_GetNumberOfBuildingsInBaseByTemplate(base, tpl);

			if (tpl->maxCount >= 0 && tpl->maxCount <= numSameBuildings)
				continue;
			/* skip if limit of BASE_SIZE*BASE_SIZE exceeded */
			if (numSameBuildings >= BASE_SIZE * BASE_SIZE)
				continue;

			/* if the building is researched add it to the list */
			if (RS_IsResearched_ptr(tpl->tech))
				B_BuildingAddToList(&buildingList, tpl);
		}
	}
	if (base->buildingCurrent)
		B_DrawBuilding(base->buildingCurrent);
	else
		cgi->UI_ExecuteConfunc("mn_buildings_reset");

	buildingNumber = LIST_Count(buildingList);
	cgi->UI_RegisterLinkedListText(TEXT_BUILDINGS, buildingList);
}
Пример #7
0
/**
 * @brief Alien containment menu init function.
 * @note Command to call this: ui_aliencont_init
 * @note Should be called whenever the alien containment menu gets active.
 */
static void AC_Init_f (void)
{
	base_t* base;
	if (cgi->Cmd_Argc() < 2)
		base = B_GetCurrentSelectedBase();
	else
		base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
	if (!base) {
		Com_Printf("No base selected\n");
		return;
	}

	cgi->UI_ExecuteConfunc("ui_aliencont_cap %d %d", CAP_GetCurrent(base, CAP_ALIENS), CAP_GetMax(base, CAP_ALIENS));
	cgi->UI_ExecuteConfunc("ui_aliencont_clear");
	if (!base->alienContainment)
		return;
	linkedList_t* list = base->alienContainment->list();
	LIST_Foreach(list, alienCargo_t, item) {
		const technology_t* tech = RS_GetTechForTeam(item->teamDef);
		cgi->UI_ExecuteConfunc("ui_aliencont_add \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" %f %d %d",
			item->teamDef->id, _(item->teamDef->name), tech->id, tech->image,
			(RS_IsResearched_ptr(tech)) ? _("Researched") : _("Awaiting autopsy"),
			(1.0f - tech->time / tech->overallTime) * 100, item->alive, item->dead);
	}
	cgi->LIST_Delete(&list);
}
Пример #8
0
/**
 * @brief sets market prices at start of the game
 * @sa CP_CampaignInit
 * @sa B_SetUpFirstBase
 * @sa BS_Load (Market load function)
 */
void BS_InitMarket (const campaign_t* campaign)
{
	int i;
	market_t* market = BS_GetMarket();

	for (i = 0; i < cgi->csi->numODs; i++) {
		const objDef_t* od = INVSH_GetItemByIDX(i);
		if (market->askItems[i] == 0) {
			market->askItems[i] = od->price;
			market->bidItems[i] = floor(market->askItems[i] * BID_FACTOR);
		}

		if (campaign->marketDef->numItems[i] <= 0)
			continue;

		if (RS_IsResearched_ptr(RS_GetTechForItem(od))) {
			/* the other relevant values were already set above */
			market->numItems[i] = campaign->marketDef->numItems[i];
		} else {
			Com_Printf("BS_InitMarket: Could not add item %s to the market - not marked as researched in campaign %s\n",
					od->id, campaign->id);
		}
	}

	for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
		const char* name = cgi->Com_DropShipTypeToShortName((humanAircraftType_t)i);
		const aircraft_t* aircraft = AIR_GetAircraft(name);
		if (market->askAircraft[i] == 0) {
			market->askAircraft[i] = aircraft->price;
			market->bidAircraft[i] = floor(market->askAircraft[i] * BID_FACTOR);
		}

		if (campaign->marketDef->numAircraft[i] <= 0)
			continue;

		if (RS_IsResearched_ptr(aircraft->tech)) {
			/* the other relevant values were already set above */
			market->numAircraft[i] = campaign->marketDef->numAircraft[i];
		} else {
			Com_Printf("BS_InitMarket: Could not add aircraft %s to the market - not marked as researched in campaign %s\n",
					aircraft->id, campaign->id);
		}
	}
}
Пример #9
0
/**
 * @brief Prints the UFOpaedia description for aircraft
 * @note Also checks whether the aircraft tech is already researched or collected
 * @sa BS_MarketAircraftDescription
 * @sa UP_Article
 */
void UP_AircraftDescription (const technology_t* tech)
{
	cgi->INV_ItemDescription(nullptr);

	/* ensure that the buffer is emptied in every case */
	upBuffer[0] = '\0';

	if (RS_IsResearched_ptr(tech)) {
		const aircraft_t* aircraft = AIR_GetAircraft(tech->provides);
		for (int i = 0; i < AIR_STATS_MAX; i++) {
			switch (i) {
			case AIR_STATS_SPEED:
				/* speed may be converted to km/h : multiply by pi / 180 * earth_radius */
				Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i),
					AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
				break;
			case AIR_STATS_MAXSPEED:
				/* speed may be converted to km/h : multiply by pi / 180 * earth_radius */
				Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i),
					AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
				break;
			case AIR_STATS_FUELSIZE:
				Q_strcat(upBuffer, sizeof(upBuffer), _("Operational range:\t%i km\n"),
					AIR_GetOperationRange(aircraft));
				break;
			case AIR_STATS_ACCURACY:
				Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i\n"), UP_AircraftStatToName(i),
					AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
				break;
			default:
				break;
			}
		}

		const baseCapacities_t cap = AIR_GetCapacityByAircraftWeight(aircraft);
		const buildingType_t buildingType = B_GetBuildingTypeByCapacity(cap);
		const building_t* building = B_GetBuildingTemplateByType(buildingType);

		Q_strcat(upBuffer, sizeof(upBuffer), _("Required Hangar:\t%s\n"), _(building->name));
		/* @note: while MAX_ACTIVETEAM limits the number of soldiers on a craft
		 * there is no use to show this in case of an UFO (would be misleading): */
		if (!AIR_IsUFO(aircraft))
			Q_strcat(upBuffer, sizeof(upBuffer), _("Max. soldiers:\t%i\n"), aircraft->maxTeamSize);
	} else if (RS_Collected_(tech)) {
		/** @todo Display crippled info and pre-research text here */
		Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this"));
	} else {
		Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this"));
	}

	cgi->Cvar_Set("mn_upmetadata", "1");
	cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, upBuffer);
	UP_DisplayTechTree(tech);
}
Пример #10
0
/**
 * @brief Open research menu.
 */
static void AC_ResearchAlien_f (void)
{
	const technology_t *tech;

	/* Can be called from everywhere. */
	if (!aliencontCurrent)
		return;

	tech = aliencontCurrent->tech;
	if (!tech)
		Com_Error(ERR_DROP, "aliencontCurrent without tech pointer");

	if (!RS_IsResearched_ptr(tech))
		cgi->UI_PushWindow("research");
}
Пример #11
0
/**
 * @brief Checks If a technology/UFOpaedia-entry will be displayed in the UFOpaedia (-list).
 * @note This does not check for different display modes (only pre-research text, what statistics, etc...). The
 * content is mostly checked in @c UP_Article
 * @return true if the tech gets displayed at all, otherwise false.
 * @sa UP_Article
 */
static bool UP_TechGetsDisplayed (const technology_t* tech)
{
	const objDef_t* item;

	assert(tech);
	/* virtual items are hidden */
	item = INVSH_GetItemByIDSilent(tech->provides);
	if (item && item->isVirtual)
		return false;
	/* Is already researched OR has collected items OR (researchable AND have description)
	 * AND not a logical block AND not redirected */
	return (RS_IsResearched_ptr(tech) || RS_Collected_(tech)
	 || (tech->statusResearchable && tech->preDescription.numDescriptions > 0))
	 && tech->type != RS_LOGIC && !tech->redirect;
}
/**
 * @brief
 * @sa BS_MarketClick_f
 * @sa BS_AddToList
 */
static void BS_MarketScroll_f (void)
{
	int i;
	base_t *base = B_GetCurrentSelectedBase();

	if (!base || buyCat >= MAX_FILTERTYPES || buyCat < 0)
		return;

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

	buyList.scroll = atoi(Cmd_Argv(1));
	assert(buyList.scroll >= 0);
	assert(!((buyList.length > MAX_MARKET_MENU_ENTRIES && buyList.scroll >= buyList.length - MAX_MARKET_MENU_ENTRIES)));

	/* now update the menu pics */
	for (i = 0; i < MAX_MARKET_MENU_ENTRIES; i++) {
		UI_ExecuteConfunc("buy_autoselli %i", i);
	}

	/* get item list */
	for (i = buyList.scroll; i < buyList.length - buyList.scroll; i++) {
		const objDef_t *od = BS_GetObjectDefition(&buyList.l[i]);

		if (i >= MAX_MARKET_MENU_ENTRIES)
			break;

		/* Check whether the item matches the proper filter, storage in current base and market. */
		if (od && (B_ItemInBase(od, base) > 0 || ccs.eMarket.numItems[od->idx]) && INV_ItemMatchesFilter(od, buyCat)) {
			const technology_t *tech = RS_GetTechForItem(od);

			UI_ExecuteConfunc("buy_show %i", i - buyList.scroll);
			BS_UpdateItem(base, i - buyList.scroll);

			/* autosell setting */
			if (!RS_IsResearched_ptr(tech))
				continue;
			if (ccs.eMarket.autosell[od->idx])
				UI_ExecuteConfunc("buy_autoselle %i", i - buyList.scroll);
			else
				UI_ExecuteConfunc("buy_autoselld %i", i - buyList.scroll);
		}
	}
}
Пример #13
0
/**
 * @brief Fills create installation / installation type selection popup
 */
static void INS_FillTypes_f (void)
{
	cgi->UI_ExecuteConfunc("installationtype_clear");
	if (INS_GetCount() < B_GetInstallationLimit()) {
		for (int i = 0; i < ccs.numInstallationTemplates; i++) {
			const installationTemplate_t* tpl = &ccs.installationTemplates[i];
			if (tpl->once && INS_HasType(tpl->type, INSTALLATION_NOT_USED))
				continue;
			if (tpl->tech == nullptr || RS_IsResearched_ptr(tpl->tech)) {
				cgi->UI_ExecuteConfunc("installationtype_add \"%s\" \"%s\" \"%s\" \"%d c\"", tpl->id, _(tpl->name),
					(tpl->buildTime > 0) ? va("%d %s", tpl->buildTime, ngettext("day", "days", tpl->buildTime)) : "-", tpl->cost);
			}
		}
	}

	/** @todo Move this out from installations code */
	if (B_GetCount() < MAX_BASES)
		cgi->UI_ExecuteConfunc("installationtype_add base \"%s\" - \"%d c\"", _("Base"), ccs.curCampaign->basecost);
}
Пример #14
0
/**
 * @brief Sets the amount of unread/new mails
 * @note This is called every campaign frame - to update ccs.numUnreadMails
 * just set it to -1 before calling this function
 * @sa CP_CampaignRun
 */
int UP_GetUnreadMails (void)
{
	const uiMessageListNodeMessage_t* m = cgi->UI_MessageGetStack();

	if (ccs.numUnreadMails != -1)
		return ccs.numUnreadMails;

	ccs.numUnreadMails = 0;

	while (m) {
		switch (m->type) {
		case MSG_RESEARCH_PROPOSAL:
			assert(m->pedia);
			if (m->pedia->mail[TECHMAIL_PRE].from && !m->pedia->mail[TECHMAIL_PRE].read)
				ccs.numUnreadMails++;
			break;
		case MSG_RESEARCH_FINISHED:
			assert(m->pedia);
			if (m->pedia->mail[TECHMAIL_RESEARCHED].from && RS_IsResearched_ptr(m->pedia) && !m->pedia->mail[TECHMAIL_RESEARCHED].read)
				ccs.numUnreadMails++;
			break;
		case MSG_NEWS:
			assert(m->pedia);
			if (m->pedia->mail[TECHMAIL_PRE].from && !m->pedia->mail[TECHMAIL_PRE].read)
				ccs.numUnreadMails++;
			if (m->pedia->mail[TECHMAIL_RESEARCHED].from && !m->pedia->mail[TECHMAIL_RESEARCHED].read)
				ccs.numUnreadMails++;
			break;
		case MSG_EVENT:
			assert(m->eventMail);
			if (!m->eventMail->read)
				ccs.numUnreadMails++;
			break;
		default:
			break;
		}
		m = m->next;
	}

	/* use strings here */
	cgi->Cvar_Set("mn_upunreadmail", "%i", ccs.numUnreadMails);
	return ccs.numUnreadMails;
}
/**
 * @brief Selects installation type to build
 */
static void INS_SelectType_f (void)
{
	if (cgi->Cmd_Argc() < 2)
		return;

	const char* id = cgi->Cmd_Argv(1);

	if (ccs.mapAction == MA_NEWINSTALLATION) {
		GEO_ResetAction();
		return;
	}

	const installationTemplate_t* tpl = INS_GetInstallationTemplateByID(id);
	if (!tpl) {
		Com_Printf("Invalid installation template\n");
		return;
	}

	if (INS_GetCount() >= B_GetInstallationLimit()) {
		Com_Printf("Maximum number of installations reached\n");
		return;
	}

	if (tpl->tech != nullptr && !RS_IsResearched_ptr(tpl->tech)) {
		Com_Printf("This type of installation is not yet researched\n");
		return;
	}

	if (tpl->once && INS_HasType(tpl->type, INSTALLATION_NOT_USED)) {
		Com_Printf("Cannot build more of this installation\n");
		return;
	}

	ccs.mapAction = MA_NEWINSTALLATION;

	/* show radar overlay (if not already displayed) */
	if (tpl->type == INSTALLATION_RADAR && !GEO_IsRadarOverlayActivated())
		GEO_SetOverlay("radar");

	INS_SetInstallationTitle(tpl->type);
	cgi->Cvar_Set("mn_installation_type", "%s", tpl->id);
}
Пример #16
0
/**
 * @brief Sets/unsets or flips the autosell property of an item on the market
 */
static void BS_SetAutosell_f (void)
{
	const objDef_t* od;
	const technology_t* tech;

	if (cgi->Cmd_Argc() < 2) {
		cgi->Com_Printf("Usage: %s <item-id> [0|1]\nWhere second parameter is the state (off/on), if omitted the autosell property will be flipped.\n",
				cgi->Cmd_Argv(0));
		return;
	}
	/* aircraft check */
	if (AIR_GetAircraftSilent(cgi->Cmd_Argv(1)) != nullptr) {
		cgi->Com_Printf("Aircraft can't be autosold!\n");
		return;
	}
	/* items */
	od = INVSH_GetItemByID(cgi->Cmd_Argv(1));
	if (!od) {
		/* no printf, INVSH_GetItemByID gave warning already */
		return;
	}
	if (od->isVirtual) {
		cgi->Com_Printf("Item %s is virtual, can't be autosold!\n", od->id);
		return;
	}
	if (od->notOnMarket) {
		cgi->Com_Printf("Item %s is not on market, can't be autosold!\n", od->id);
		return;
	}
	tech = RS_GetTechForItem(od);
	/* Don't allow to enable autosell for items not researched. */
	if (!RS_IsResearched_ptr(tech)) {
		cgi->Com_Printf("Item %s is not researched, can't be autosold!\n", od->id);
		return;
	}
	if (cgi->Cmd_Argc() >= 3)
		ccs.eMarket.autosell[od->idx] = atoi(cgi->Cmd_Argv(2));
	else
		ccs.eMarket.autosell[od->idx] = ! ccs.eMarket.autosell[od->idx];
}
Пример #17
0
/**
 * @brief Returns if storing a specific life form is supported by the containment
 * @param[in] team Pointer to the alien Team Definition
 */
bool AlienContainment::isLifeSupported(const teamDef_t* team)
{
	/* No team - not supported */
	if (!team)
		return false;

	/* humans supported */
	if (!CHRSH_IsTeamDefAlien(team))
		return true;

	/* Robots are supported */
	if (CHRSH_IsTeamDefRobot(team))
		return true;

	/* Organic aliens need breathing apparatus known */
	/** @todo find a way that doesn't need a tech ID hardcoded */
	const technology_t* tech = RS_GetTechByID(BREATHINGAPPARATUS_TECH);
	if (!tech)
		return false;

	return RS_IsResearched_ptr(tech);
}
/**
 * @brief Enable or disable autosell option for given itemtype.
 */
static void BS_Autosell_f (void)
{
	int num;
	const objDef_t *item;
	base_t *base = B_GetCurrentSelectedBase();

	/* Can be called from everywhere. */
	if (!base)
		return;

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

	num = atoi(Cmd_Argv(1));
	Com_DPrintf(DEBUG_CLIENT, "BS_Autosell_f: listnumber %i\n", num);
	if (num < 0 || num >= buyList.length)
		return;

	item = BS_GetObjectDefition(&buyList.l[num + buyList.scroll]);
	assert(item);

	if (ccs.eMarket.autosell[item->idx]) {
		ccs.eMarket.autosell[item->idx] = qfalse;
		Com_DPrintf(DEBUG_CLIENT, "item name: %s, autosell false\n", item->name);
	} else {
		const technology_t *tech = RS_GetTechForItem(item);
		/* Don't allow to enable autosell for items not researched. */
		if (!RS_IsResearched_ptr(tech))
			return;
		ccs.eMarket.autosell[item->idx] = qtrue;
		Com_DPrintf(DEBUG_CLIENT, "item name: %s, autosell true\n", item->name);
	}

	/* Reinit the menu. */
	BS_BuyType(base);
}
Пример #19
0
/**
 * @brief Updates the alienscont menu.
 */
static void AC_UpdateMenu (const base_t *base)
{

	Cvar_Set("mn_al_alientype", "");
	Cvar_Set("mn_al_alienimage", "");
	Cvar_SetValue("mn_al_dead", 0);
	Cvar_SetValue("mn_al_alive", 0);
	Cvar_SetValue("mn_al_capacity", CAP_GetCurrent(base, CAP_ALIENS));
	Cvar_SetValue("mn_al_capacity_max", CAP_GetMax(base, CAP_ALIENS));

	/* Reset list. */
	cgi->UI_ExecuteConfunc("aliencont_clear");
	if (B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT)) {
		const aliensCont_t *containment = base->alienscont;
		int i, j;
		for (i = 0, j = 0; i < ccs.numAliensTD; i++) {
			if (j < MAX_AC_MENU_ENTRIES) {
				if (containment[i].teamDef) {
					const technology_t *tech = containment[i].tech;
					if (!tech) {
						Com_Printf("AC_UpdateMenu: Tech entry for containment %i not set!\n", i);
						/* to let the click function still work */
						continue;
					}
					if (!aliencontCurrent) {
						aliencontCurrent = &containment[i];
					}
					if (containment[i].amountAlive > 0 || containment[i].amountDead > 0) {
						/* Generate a list entry. */
						if (RS_IsResearched_ptr(tech)) {
							Cvar_Set(va("mn_ac_statusstr%i", j), _("Researched"));
						} else {
							Cvar_Set(va("mn_ac_statusstr%i", j), _("Awaiting autopsy"));
							if (!containment[i].amountDead) {
								cgi->UI_ExecuteConfunc("aliencontkill %i", j);
							} else {
								cgi->UI_ExecuteConfunc("aliencontneedautopsy %i", j);
							}
						}
						Cvar_SetValue(va("mn_ac_progress%i", j), (1 - tech->time / tech->overallTime) * 100);
						/* Display name in the correct list-entry. */
						Cvar_Set(va("mn_ac_name%i", j), _(containment[i].teamDef->name));
						/* Display amount of dead aliens in the correct list-entry. */
						Cvar_SetValue(va("mn_ac_dead%i", j), containment[i].amountDead);
						/* Display number of live aliens in the correct list-entry. */
						Cvar_SetValue(va("mn_ac_alive%i", j), containment[i].amountAlive);
						j++;
					}
				}
			}
		}

		numAliensOnList = j;

		for (; j < MAX_AC_MENU_ENTRIES; j++) {
			Cvar_Set(va("mn_ac_statusstr%i", j), _("Free slot"));
			Cvar_Set(va("mn_ac_name%i", j), _("None"));
			Cvar_Set(va("mn_ac_dead%i", j), "");
			Cvar_Set(va("mn_ac_alive%i", j), "");
			Cvar_SetValue(va("mn_ac_progress%i", j), 0);
		}
	}

	/** @todo Select the containment we (maybe) just clicked again */
	AC_AlienClick(base, 0);
}
Пример #20
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);
}
Пример #21
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);
		}
	}
}
/**
 * @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;
}
Пример #23
0
/**
 * @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;
	}
Пример #24
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)
{
	base_t* base = B_GetCurrentSelectedBase();

	if (!base)
		return;

	/* make sure the credits cvar is up-to-date */
	CP_UpdateCredits(ccs.credits);

	/* 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 (int i = 0; i < ccs.numBuildingTemplates; i++) {
		const building_t* b = &ccs.buildingTemplates[i];

		/* 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;

		const baseCapacities_t capType = B_GetCapacityFromBuildingType(b->buildingType);
		if (capType == MAX_CAP)
			continue;

		const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl);
		if (count < 1)
			continue;

		const capacities_t& cap = *CAP_Get(base, capType);
		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)) {
		AIR_ForeachFromBase(aircraft, base) {
			cgi->UI_ExecuteConfunc("show_aircraft %i \"%s\" \"%s\" \"%s\" %i", aircraft->idx, aircraft->name, aircraft->id, AIR_AircraftStatusToName(aircraft), AIR_IsAircraftInBase(aircraft));
		}
	}
Пример #25
0
/**
 * @brief Display only the TEXT_UFOPEDIA part for a given technology
 * @param[in] tech The technology_t pointer to print the UFOpaedia article for
 * @param[in] mail The mail parameters in case we produce a mail
 * @sa UP_Article
 */
static void UP_Article (technology_t* tech, eventMail_t* mail)
{
	UP_ChangeDisplay(UFOPEDIA_ARTICLE);

	if (tech) {
		if (tech->mdl)
			cgi->Cvar_Set("mn_upmodel_top", "%s", tech->mdl);
		else
			cgi->Cvar_Set("mn_upmodel_top", "");

		if (tech->image)
			cgi->Cvar_Set("mn_upimage_top", "%s", tech->image);
		else
			cgi->Cvar_Set("mn_upimage_top", "");

		cgi->Cvar_Set("mn_upmodel_bottom", "");

		if (tech->type == RS_WEAPON)
			UP_DrawAssociatedAmmo(tech);
		cgi->Cvar_Set("mn_uprequirement", "");
		cgi->Cvar_Set("mn_upmetadata", "");
	}

	cgi->UI_ResetData(TEXT_UFOPEDIA);
	cgi->UI_ResetData(TEXT_UFOPEDIA_REQUIREMENT);

	if (mail) {
		/* event mail */
		cgi->Cvar_SetValue("mn_uppreavailable", 0);
		cgi->Cvar_SetValue("mn_updisplay", UFOPEDIA_CHAPTERS);
		UP_SetMailHeader(nullptr, TECHMAIL_PRE, mail);
		cgi->UI_RegisterText(TEXT_UFOPEDIA, _(mail->body));
		/* This allows us to use the index button in the UFOpaedia,
		 * eventMails don't have any chapter to go back to. */
		upDisplay = UFOPEDIA_INDEX;
	} else if (tech) {
		currentChapter = tech->upChapter;
		upCurrentTech = tech;

		/* Reset itemdescription */
		cgi->UI_ExecuteConfunc("itemdesc_view 0 0;");
		if (RS_IsResearched_ptr(tech)) {
			cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s (complete)"), _(tech->name));
			/* If researched -> display research text */
			cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->description)));
			if (tech->preDescription.numDescriptions > 0) {
				/* Display pre-research text and the buttons if a pre-research text is available. */
				if (mn_uppretext->integer) {
					cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->preDescription)));
					UP_SetMailHeader(tech, TECHMAIL_PRE, nullptr);
				} else {
					UP_SetMailHeader(tech, TECHMAIL_RESEARCHED, nullptr);
				}
				cgi->Cvar_SetValue("mn_uppreavailable", 1);
			} else {
				/* Do not display the pre-research-text button if none is available (no need to even bother clicking there). */
				cgi->Cvar_SetValue("mn_uppreavailable", 0);
				cgi->Cvar_SetValue("mn_updisplay", UFOPEDIA_CHAPTERS);
				UP_SetMailHeader(tech, TECHMAIL_RESEARCHED, nullptr);
			}

			switch (tech->type) {
			case RS_ARMOUR:
			case RS_WEAPON:
				for (int i = 0; i < cgi->csi->numODs; i++) {
					const objDef_t* od = INVSH_GetItemByIDX(i);
					if (Q_streq(tech->provides, od->id)) {
						cgi->INV_ItemDescription(od);
						UP_DisplayTechTree(tech);
						cgi->Cvar_Set("mn_upmetadata", "1");
						break;
					}
				}
				break;
			case RS_TECH:
				UP_DisplayTechTree(tech);
				break;
			case RS_CRAFT:
				UP_AircraftDescription(tech);
				break;
			case RS_CRAFTITEM:
				UP_AircraftItemDescription(INVSH_GetItemByID(tech->provides));
				break;
			case RS_BUILDING:
				UP_BuildingDescription(tech);
				break;
			case RS_UGV:
				UP_UGVDescription(cgi->Com_GetUGVByIDSilent(tech->provides));
				break;
			default:
				break;
			}
		/* see also UP_TechGetsDisplayed */
		} else if (RS_Collected_(tech) || (tech->statusResearchable && tech->preDescription.numDescriptions > 0)) {
			/* This tech has something collected or has a research proposal. (i.e. pre-research text) */
			cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s"), _(tech->name));
			/* Not researched but some items collected -> display pre-research text if available. */
			if (tech->preDescription.numDescriptions > 0) {
				cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->preDescription)));
				UP_SetMailHeader(tech, TECHMAIL_PRE, nullptr);
			} else {
				cgi->UI_RegisterText(TEXT_UFOPEDIA, _("No pre-research description available."));
			}
		} else {
			cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s"), _(tech->name));
			cgi->UI_ResetData(TEXT_UFOPEDIA);
		}
	} else {
		cgi->Com_Error(ERR_DROP, "UP_Article: No mail or tech given");
	}
}
Пример #26
0
/**
 * @brief Fills the battery list, descriptions, and weapons in slots
 * of the basedefence equip menu
 */
static void BDEF_BaseDefenceMenuUpdate_f (void)
{
	char type[MAX_VAR];
	base_t* base = B_GetCurrentSelectedBase();
	installation_t* installation = INS_GetCurrentSelectedInstallation();
	aircraftItemType_t bdefType;
	linkedList_t* slotList = nullptr;
	const bool missileResearched = RS_IsResearched_ptr(RS_GetTechByID("rs_building_missile"));
	const bool laserResearched = RS_IsResearched_ptr(RS_GetTechByID("rs_building_laser"));

	if (cgi->Cmd_Argc() != 2)
		type[0] = '\0';
	else
		Q_strncpyz(type, cgi->Cmd_Argv(1), sizeof(type));

	/* don't let old links appear on this menu */
	cgi->UI_ResetData(TEXT_BASEDEFENCE_LIST);
	cgi->UI_ResetData(TEXT_LIST);
	cgi->UI_ResetData(TEXT_ITEMDESCRIPTION);

	/* base or installation should not be nullptr because we are in the menu of this base or installation */
	if (!base && !installation)
		return;

	/* base and installation should not both be set. This function requires one or the other set. */
	if (base && installation) {
		Sys_Error("BDEF_BaseDefenceMenuUpdate_f: Both the base and installation are set");
		return;
	}

	cgi->Cvar_Set("mn_target", _("None"));
	cgi->UI_ExecuteConfunc("setautofire disable");
	if (installation) {
		/* Every slot aims the same target */
		if (installation->numBatteries) {
			cgi->UI_ExecuteConfunc("setautofire %i", installation->batteries[0].autofire);

			if (installation->batteries[0].target)
				cgi->Cvar_Set("mn_target", "%s", UFO_GetName(installation->batteries[0].target));
		}
	} else if (base) {
		bool autofire = false;
		/* Every slot aims the same target */
		if (base->numBatteries) {
			autofire |= base->batteries[0].autofire;
			if (base->batteries[0].target)
				cgi->Cvar_Set("mn_target", "%s", UFO_GetName(base->batteries[0].target));
		}
		if (base->numLasers) {
			autofire |= base->lasers[0].autofire;
			if (base->lasers[0].target && !base->batteries[0].target)
				cgi->Cvar_Set("mn_target", "%s", UFO_GetName(base->lasers[0].target));
		}
		if (base->numBatteries || base->numLasers)
			cgi->UI_ExecuteConfunc("setautofire %i", autofire);
	}

	/* Check if we can change to laser or missile */
	if (base) {
		cgi->UI_ExecuteConfunc("set_defencetypes %s %s",
				(!missileResearched) ? "na" : (base && base->numBatteries > 0) ? "enable" : "disable",
				(!laserResearched) ? "na" : (base && base->numLasers > 0) ? "enable" : "disable");
	} else if (installation) {
		cgi->UI_ExecuteConfunc("set_defencetypes %s %s",
				(!missileResearched) ? "na" : (installation && installation->installationStatus == INSTALLATION_WORKING
						&& installation->numBatteries > 0) ? "enable" : "disable", "na");
	}

	if (Q_streq(type, "missile"))
		bdefType = AC_ITEM_BASE_MISSILE;
	else if (Q_streq(type, "laser"))
		bdefType = AC_ITEM_BASE_LASER;
	else	/* info page */
		return;

	/* Check that the base or installation has at least 1 battery */
	if (base) {
		if (base->numBatteries + base->numLasers < 1) {
			Com_Printf("BDEF_BaseDefenceMenuUpdate_f: there is no defence battery in this base: you shouldn't be in this function.\n");
			return;
		}
	} else if (installation) {
		if (installation->installationStatus != INSTALLATION_WORKING) {
			Com_Printf("BDEF_BaseDefenceMenuUpdate_f: installation isn't working: you shouldn't be in this function.\n");
			return;
		} else if (installation->installationTemplate->maxBatteries < 1) {
			Com_Printf("BDEF_BaseDefenceMenuUpdate_f: there is no defence battery in this installation: you shouldn't be in this function.\n");
			return;
		}
	}

	if (installation) {
		/* we are in the installation defence menu */
		if (installation->installationTemplate->maxBatteries == 0) {
			cgi->LIST_AddString(&slotList, _("No defence of this type in this installation"));
		} else {
			BDEF_FillSlotList(installation->batteries, installation->installationTemplate->maxBatteries, &slotList);
		}
	} else if (bdefType == AC_ITEM_BASE_MISSILE) {
		/* we are in the base defence menu for missile */
		if (base->numBatteries == 0) {
			cgi->LIST_AddString(&slotList, _("No defence of this type in this base"));
		} else {
			BDEF_FillSlotList(base->batteries, base->numActiveBatteries, &slotList);
		}
	} else if (bdefType == AC_ITEM_BASE_LASER) {
		/* we are in the base defence menu for laser */
		if (base->numLasers == 0) {
			cgi->LIST_AddString(&slotList, _("No defence of this type in this base"));
		} else {
			BDEF_FillSlotList(base->lasers, base->numActiveLasers, &slotList);
		}
	} else {
		Com_Printf("BDEF_BaseDefenceMenuUpdate_f: unknown bdefType.\n");
		return;
	}
	cgi->UI_RegisterLinkedListText(TEXT_BASEDEFENCE_LIST, slotList);
}
/**
 * @brief Updates the Buy/Sell menu list.
 * @param[in] base Pointer to the base to buy/sell at
 * @sa BS_BuyType_f
 */
static void BS_BuyType (const base_t *base)
{
	const objDef_t *od;
	int i, j = 0;
	char tmpbuf[MAX_VAR];

	if (!base || buyCat >= MAX_FILTERTYPES || buyCat < 0)
		return;

	CP_UpdateCredits(ccs.credits);

	bsMarketNames = NULL;
	bsMarketStorage = NULL;
	bsMarketMarket = NULL;
	bsMarketPrices = NULL;
	UI_ResetData(TEXT_ITEMDESCRIPTION);

	/* hide autosell checkboxes by default */
	for (i = 0; i < MAX_MARKET_MENU_ENTRIES; i++) {
		UI_ExecuteConfunc("buy_autoselli %i", i);
	}

	switch (buyCat) {
	case FILTER_AIRCRAFT:	/* Aircraft */
		{
		const aircraft_t *aircraftTemplate;
		for (i = 0, j = 0, aircraftTemplate = ccs.aircraftTemplates; i < ccs.numAircraftTemplates; i++, aircraftTemplate++) {
			if (!BS_AircraftIsOnMarket(aircraftTemplate))
				continue;
			assert(aircraftTemplate->tech);
			if (BS_GetStorageAmountInBase(base, aircraftTemplate->id) + BS_GetAircraftOnMarket(aircraftTemplate) > 0) {
				if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
					UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
				}
				BS_AddToList(aircraftTemplate->name, BS_GetStorageAmountInBase(base, aircraftTemplate->id),
						BS_GetAircraftOnMarket(aircraftTemplate), BS_GetAircraftBuyingPrice(aircraftTemplate));
				if (j >= MAX_BUYLIST)
					Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n");
				buyList.l[j].item = NULL;
				buyList.l[j].aircraft = aircraftTemplate;
				buyList.length = j + 1;
				BS_UpdateItem(base, j - buyList.scroll);
				j++;
			}
		}
		}
		break;
	case FILTER_CRAFTITEM:	/* Aircraft items */
		/* get item list */
		for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) {
			if (!BS_IsOnMarket(od))
				continue;
			/* Check whether the item matches the proper filter, storage in current base and market. */
			if ((B_ItemInBase(od, base) || ccs.eMarket.numItems[i])
			 && INV_ItemMatchesFilter(od, FILTER_CRAFTITEM)) {
				if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
					const technology_t *tech = RS_GetTechForItem(od);

					UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
					if (RS_IsResearched_ptr(tech)) {
						if (ccs.eMarket.autosell[i])
							UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll);
						else
							UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll);
					}
				}
				BS_AddToList(od->name, B_ItemInBase(od, base), ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od));
				if (j >= MAX_BUYLIST)
					Com_Error(ERR_DROP, "Increase the MAX_FILTERLIST value to handle that much items\n");
				buyList.l[j].item = od;
				buyList.l[j].aircraft = NULL;
				buyList.length = j + 1;
				BS_UpdateItem(base, j - buyList.scroll);
				j++;
			}
		}
		break;
	default:	/* Normal items */
		if (buyCat < MAX_SOLDIER_FILTERTYPES || buyCat == FILTER_DUMMY) {
			/* get item list */
			for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) {
				if (!BS_IsOnMarket(od))
					continue;
				/* Check whether the item matches the proper filter, storage in current base and market. */
				if ((B_ItemInBase(od, base) || ccs.eMarket.numItems[i]) && INV_ItemMatchesFilter(od, buyCat)) {
					BS_AddToList(od->name, B_ItemInBase(od, base), ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od));
					/* Set state of Autosell button. */
					if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
						const technology_t *tech = RS_GetTechForItem(od);

						UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
						if (RS_IsResearched_ptr(tech)) {
							if (ccs.eMarket.autosell[i])
								UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll);
							else
								UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll);
						}
					}

					if (j >= MAX_BUYLIST)
						Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n");
					buyList.l[j].item = od;
					buyList.l[j].aircraft = NULL;
					buyList.length = j + 1;
					BS_UpdateItem(base, j - buyList.scroll);
					j++;
				}
			}
		}
		break;
	}

	for (; j < MAX_MARKET_MENU_ENTRIES; j++) {
		/* Hide the rest of the entries. */
		UI_ExecuteConfunc("buy_hide %i", j);
	}

	/* Update some menu cvars. */
	/* Set up base capacities. */
	Com_sprintf(tmpbuf, sizeof(tmpbuf), "%i/%i", CAP_GetCurrent(base, CAP_ITEMS),
		CAP_GetMax(base, CAP_ITEMS));
	Cvar_Set("mn_bs_storage", tmpbuf);

	/* select first item */
	if (buyList.length) {
		switch (buyCat) {	/** @sa BS_MarketClick_f */
		case FILTER_AIRCRAFT:
			BS_MarketAircraftDescription(buyList.l[0].aircraft);
			break;
		case FILTER_CRAFTITEM:
			Cvar_Set("mn_aircraftname", "");	/** @todo Use craftitem name here? See also BS_MarketClick_f */
			/* Select current item or first one. */
			if (currentSelectedMenuEntry)
				UP_AircraftItemDescription(currentSelectedMenuEntry);
			else
				UP_AircraftItemDescription(buyList.l[0].item);
			break;
		default:
			assert(buyCat != MAX_FILTERTYPES);
			/* Select current item or first one. */
			if (currentSelectedMenuEntry)
				INV_ItemDescription(currentSelectedMenuEntry);
			else
				INV_ItemDescription(buyList.l[0].item);
			break;
		}
	} else {
		/* reset description */
		INV_ItemDescription(NULL);
	}

	UI_RegisterLinkedListText(TEXT_MARKET_NAMES, bsMarketNames);
	UI_RegisterLinkedListText(TEXT_MARKET_STORAGE, bsMarketStorage);
	UI_RegisterLinkedListText(TEXT_MARKET_MARKET, bsMarketMarket);
	UI_RegisterLinkedListText(TEXT_MARKET_PRICES, bsMarketPrices);
}
Пример #28
0
/**
 * @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);
}
Пример #29
0
/**
 * @brief make number of items change every day.
 * @sa CP_CampaignRun
 * @sa daily called
 * @note This function makes items number on market slowly reach the asymptotic number of items defined in equipment.ufo
 * If an item has just been researched, it's not available on market until RESEARCH_LIMIT_DELAY days is reached.
 */
void CP_CampaignRunMarket (campaign_t* campaign)
{
	int i;
	const float TYPICAL_TIME = 10.f;			/**< Number of days to reach the asymptotic number of items */
	const int RESEARCH_LIMIT_DELAY = 30;		/**< Numbers of days after end of research to wait in order to have
												 * items added on market */
	market_t* market = BS_GetMarket();

	assert(campaign->marketDef);
	assert(campaign->asymptoticMarketDef);

	for (i = 0; i < cgi->csi->numODs; i++) {
		const objDef_t* od = INVSH_GetItemByIDX(i);
		const technology_t* tech = RS_GetTechForItem(od);
		int asymptoticNumber;

		if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numItems[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) {
			/* if items are researched for more than RESEARCH_LIMIT_DELAY or was on the initial market,
			 * there number tend to the value defined in equipment.ufo.
			 * This value is the asymptotic value if it is not 0, or initial value else */
			asymptoticNumber = campaign->asymptoticMarketDef->numItems[i] ? campaign->asymptoticMarketDef->numItems[i] : campaign->marketDef->numItems[i];
		} else {
			/* items that have just been researched don't appear on market, but they can disappear */
			asymptoticNumber = 0;
		}

		/* Store the evolution of the market in currentEvolution */
		market->currentEvolutionItems[i] += (asymptoticNumber - market->numItems[i]) / TYPICAL_TIME;

		/* Check if new items appeared or disappeared on market */
		if (fabs(market->currentEvolutionItems[i]) >= 1.0f) {
			const int num = (int)(market->currentEvolutionItems[i]);
			if (num >= 0)
				BS_AddItemToMarket(od, num);
			else
				BS_RemoveItemFromMarket(od, -num);
			market->currentEvolutionItems[i] -= num;
		}
	}

	for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
		const humanAircraftType_t type = (humanAircraftType_t)i;
		const char* aircraftID = cgi->Com_DropShipTypeToShortName(type);
		const aircraft_t* aircraft = AIR_GetAircraft(aircraftID);
		const technology_t* tech = aircraft->tech;
		int asymptoticNumber;

		if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numAircraft[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) {
			/* if aircraft is researched for more than RESEARCH_LIMIT_DELAY or was on the initial market,
			 * there number tend to the value defined in equipment.ufo.
			 * This value is the asymptotic value if it is not 0, or initial value else */
			asymptoticNumber = campaign->asymptoticMarketDef->numAircraft[i] ? campaign->asymptoticMarketDef->numAircraft[i] : campaign->marketDef->numAircraft[i];
		} else {
			/* items that have just been researched don't appear on market, but they can disappear */
			asymptoticNumber = 0;
		}
		/* Store the evolution of the market in currentEvolution */
		market->currentEvolutionAircraft[i] += (asymptoticNumber - market->numAircraft[i]) / TYPICAL_TIME;

		/* Check if new items appeared or disappeared on market */
		if (fabs(market->currentEvolutionAircraft[i]) >= 1.0f) {
			const int num = (int)(market->currentEvolutionAircraft[i]);
			if (num >= 0)
				BS_AddAircraftToMarket(aircraft, num);
			else
				BS_RemoveAircraftFromMarket(aircraft, -num);
			market->currentEvolutionAircraft[i] -= num;
		}
	}
}
Пример #30
0
/**
 * @brief Puts alien cargo into Alien Containment.
 * @param[in] aircraft Aircraft transporting cargo to homebase.
 * @sa B_AircraftReturnedToHomeBase
 * @sa AL_FillInContainment
 * @note an event mail about missing breathing tech will be triggered if necessary.
 */
void AL_AddAliens (aircraft_t *aircraft)
{
	base_t *toBase;
	const aliensTmp_t *cargo;
	int alienCargoTypes;
	int i;
	int j;
	qboolean limit = qfalse;
	qboolean messageAlreadySet = qfalse;
	technology_t *breathingTech;
	qboolean alienBreathing = qfalse;
	const objDef_t *alienBreathingObjDef;

	assert(aircraft);
	toBase = aircraft->homebase;
	assert(toBase);

	cargo = AL_GetAircraftAlienCargo(aircraft);
	alienCargoTypes = AL_GetAircraftAlienCargoTypes(aircraft);

	if (alienCargoTypes == 0)
		return;

	if (!B_GetBuildingStatus(toBase, B_ALIEN_CONTAINMENT)) {
		MS_AddNewMessage(_("Notice"), _("You cannot process aliens yet. Alien Containment not ready in this base."), qfalse, MSG_STANDARD, NULL);
		return;
	}

	breathingTech = RS_GetTechByID(BREATHINGAPPARATUS_TECH);
	if (!breathingTech)
		Com_Error(ERR_DROP, "AL_AddAliens: Could not get breathing apparatus tech definition");
	alienBreathing = RS_IsResearched_ptr(breathingTech);
	alienBreathingObjDef = INVSH_GetItemByID(breathingTech->provides);
	if (!alienBreathingObjDef)
		Com_Error(ERR_DROP, "AL_AddAliens: Could not get breathing apparatus item definition");

	for (i = 0; i < alienCargoTypes; i++) {
		for (j = 0; j < ccs.numAliensTD; j++) {
			assert(toBase->alienscont[j].teamDef);
			assert(cargo[i].teamDef);

			if (toBase->alienscont[j].teamDef == cargo[i].teamDef) {
				toBase->alienscont[j].amountDead += cargo[i].amountDead;
				/* Add breathing apparatuses to aircraft cargo so that they are processed with other collected items */
				AII_CollectItem(aircraft, alienBreathingObjDef, cargo[i].amountDead);
				if (cargo[i].amountAlive <= 0)
					continue;
				if (!alienBreathing && !CHRSH_IsTeamDefRobot(cargo[i].teamDef)) {
					/* We can not store living (i.e. no robots or dead bodies) aliens without rs_alien_breathing tech */
					toBase->alienscont[j].amountDead += cargo[i].amountAlive;
					/* Add breathing apparatuses as well */
					AII_CollectItem(aircraft, alienBreathingObjDef, cargo[i].amountAlive);
					/* only once */
					if (!messageAlreadySet) {
						MS_AddNewMessage(_("Notice"), _("You can't hold live aliens yet. Aliens died."), qfalse, MSG_DEATH, NULL);
						messageAlreadySet = qtrue;
					}
					if (!ccs.breathingMailSent) {
						Cmd_ExecuteString("addeventmail alienbreathing");
						ccs.breathingMailSent = qtrue;
					}
				} else {
					int k;

					for (k = 0; k < cargo[i].amountAlive; k++) {
						/* Check base capacity. */
						if (AL_CheckAliveFreeSpace(toBase, NULL, 1)) {
							AL_ChangeAliveAlienNumber(toBase, &(toBase->alienscont[j]), 1);
						} else {
							/* Every exceeding alien is killed
							 * Display a message only when first one is killed */
							if (!limit) {
								toBase->capacities[CAP_ALIENS].cur = toBase->capacities[CAP_ALIENS].max;
								MS_AddNewMessage(_("Notice"), _("You don't have enough space in Alien Containment. Some aliens got killed."), qfalse, MSG_STANDARD, NULL);
								limit = qtrue;
							}
							/* Just kill aliens which don't fit the limit. */
							toBase->alienscont[j].amountDead++;
							AII_CollectItem(aircraft, alienBreathingObjDef, 1);
						}
					}
					/* only once */
					if (!messageAlreadySet) {
						MS_AddNewMessage(_("Notice"), _("You've captured new aliens."), qfalse, MSG_STANDARD, NULL);
						messageAlreadySet = qtrue;
					}
				}
				break;
			}
		}
	}

	for (i = 0; i < ccs.numAliensTD; i++) {
		aliensCont_t *ac = &toBase->alienscont[i];
		technology_t *tech = ac->tech;
#ifdef DEBUG
		if (!tech)
			Sys_Error("AL_AddAliens: Failed to initialize the tech for '%s'\n", ac->teamDef->name);
#endif
		/* we need this to let RS_Collected_ return true */
		if (ac->amountAlive + ac->amountDead > 0)
			RS_MarkCollected(tech);
#ifdef DEBUG
		/* print all of them */
		if (ac->amountAlive > 0)
			Com_DPrintf(DEBUG_CLIENT, "AL_AddAliens alive: %s amount: %i\n", ac->teamDef->name, ac->amountAlive);
		if (ac->amountDead > 0)
			Com_DPrintf(DEBUG_CLIENT, "AL_AddAliens bodies: %s amount: %i\n", ac->teamDef->name, ac->amountDead);
#endif
	}

	/* we shouldn't have any more aliens on the aircraft after this */
	AL_SetAircraftAlienCargoTypes(aircraft, 0);
}