/**
 * @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;
}
Esempio n. 2
0
/**
 * @brief Sells the given UGV with all the equipment.
 * @param robot The employee record of the UGV to sell
 * @return @c true if the ugv could get sold, @c false otherwise
 * @todo Implement this correctly once we have UGV
 */
bool BS_SellUGV (Employee* robot)
{
	const objDef_t* ugvWeapon;
	const ugv_t* ugv;
	base_t* base;

	if (!robot)
		cgi->Com_Error(ERR_DROP, "Selling nullptr UGV!");
	if (!robot->getUGV())
		cgi->Com_Error(ERR_DROP, "Selling invalid UGV with UCN: %i", robot->chr.ucn);
	ugv = robot->getUGV();
	base = robot->baseHired;

	/* Check if we have a weapon for this ugv in the market to sell it. */
	ugvWeapon = INVSH_GetItemByID(ugv->weapon);
	if (!ugvWeapon)
		cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get wepaon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id);

	if (!robot->unhire()) {
		/** @todo message - Couldn't fire employee. */
		Com_DPrintf(DEBUG_CLIENT, "Couldn't sell/fire robot/ugv.\n");
		return false;
	}

	BS_AddItemToMarket(ugvWeapon, 1);
	CP_UpdateCredits(ccs.credits + ugv->price);
	B_AddToStorage(base, ugvWeapon, -1);

	return true;
}
Esempio n. 3
0
/**
 * @brief Buys the given UGV
 * @param[in] ugv The ugv template of the UGV to buy
 * @param[out] base Base to buy at
 * @return @c true if the ugv could get bought, @c false otherwise
 * @todo Implement this correctly once we have UGV
 */
bool BS_BuyUGV (const ugv_t* ugv, base_t* base)
{
	const objDef_t* ugvWeapon;

	if (!ugv)
		cgi->Com_Error(ERR_DROP, "BS_BuyUGV: Called on nullptr UGV!");
	if (!base)
		cgi->Com_Error(ERR_DROP, "BS_BuyUGV: Called on nullptr base!");
	ugvWeapon = INVSH_GetItemByID(ugv->weapon);
	if (!ugvWeapon)
		cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get weapon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id);

	if (ccs.credits < ugv->price)
		return false;
	if (E_CountUnhiredRobotsByType(ugv) <= 0)
		return false;
	if (BS_GetItemOnMarket(ugvWeapon) <= 0)
		return false;
	if (CAP_GetFreeCapacity(base, CAP_ITEMS) < UGV_SIZE + ugvWeapon->size)
		return false;
	if (!E_HireRobot(base, ugv))
		return false;

	BS_RemoveItemFromMarket(ugvWeapon, 1);
	CP_UpdateCredits(ccs.credits - ugv->price);
	B_AddToStorage(base, ugvWeapon, 1);

	return true;
}
Esempio n. 4
0
/**
 * @brief Set the ammo model to display to selected ammo (only for a reloadable weapon)
 * @param tech technology_t pointer for the weapon's tech
 * @sa UP_Article
 */
static void UP_DrawAssociatedAmmo (const technology_t* tech)
{
	const objDef_t* od = INVSH_GetItemByID(tech->provides);
	/* If this is a weapon, we display the model of the associated ammunition in the lower right */
	if (od->numAmmos > 0) {
		const technology_t* associated = RS_GetTechForItem(od->ammos[0]);
		cgi->Cvar_Set("mn_upmodel_bottom", "%s", associated->mdl);
	}
}
Esempio n. 5
0
/**
 * @brief Load callback for savegames in XML Format
 * @param[in] parent XML Node structure, where we get the information from
 */
bool AIRFIGHT_LoadXML (xmlNode_t* parent)
{
	int i;
	xmlNode_t* node;

	for (i = 0, node = cgi->XML_GetNode(parent, SAVE_AIRFIGHT_PROJECTILE); i < MAX_PROJECTILESONGEOSCAPE && node;
			node = cgi->XML_GetNextNode(node, parent, SAVE_AIRFIGHT_PROJECTILE), i++) {
		technology_t* tech = RS_GetTechByProvided(cgi->XML_GetString(node, SAVE_AIRFIGHT_ITEMID));
		int j;
		xmlNode_t* positions;
		xmlNode_t* attackingAircraft;
		xmlNode_t* aimedAircraft;
		aircraftProjectile_t* projectile = &ccs.projectiles[i];

		if (!tech) {
			Com_Printf("AIR_Load: Could not get technology of projectile %i\n", i);
			return false;
		}

		projectile->aircraftItem = INVSH_GetItemByID(tech->provides);

		for (j = 0, positions = cgi->XML_GetPos2(node, SAVE_AIRFIGHT_POS, projectile->pos[0]); j < MAX_MULTIPLE_PROJECTILES && positions;
			j++, positions = cgi->XML_GetNextPos2(positions, node, SAVE_AIRFIGHT_POS, projectile->pos[j]))
			;
		projectile->numProjectiles = j;
		cgi->XML_GetPos3(node, SAVE_AIRFIGHT_IDLETARGET, projectile->idleTarget);

		projectile->time = cgi->XML_GetInt(node, SAVE_AIRFIGHT_TIME, 0);
		projectile->angle = cgi->XML_GetFloat(node, SAVE_AIRFIGHT_ANGLE, 0.0);
		projectile->bullets = cgi->XML_GetBool(node, SAVE_AIRFIGHT_BULLET, false);
		projectile->beam = cgi->XML_GetBool(node, SAVE_AIRFIGHT_BEAM, false);

		if ((attackingAircraft = cgi->XML_GetNode(node, SAVE_AIRFIGHT_ATTACKINGAIRCRAFT))) {
			if (cgi->XML_GetBool(attackingAircraft, SAVE_AIRFIGHT_ISUFO, false))
				/** @todo 0 as default might be incorrect */
				projectile->attackingAircraft = UFO_GetByIDX(cgi->XML_GetInt(attackingAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, 0));
			else
				projectile->attackingAircraft = AIR_AircraftGetFromIDX(cgi->XML_GetInt(attackingAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, AIRCRAFT_INVALID));
		} else {
			projectile->attackingAircraft = nullptr;
		}
		cgi->XML_GetPos3(node, SAVE_AIRFIGHT_ATTACKERPOS, projectile->attackerPos);

		if ((aimedAircraft = cgi->XML_GetNode(node, SAVE_AIRFIGHT_AIMEDAIRCRAFT))) {
			if (cgi->XML_GetBool(aimedAircraft, SAVE_AIRFIGHT_ISUFO, false))
				/** @todo 0 as default might be incorrect */
				projectile->aimedAircraft = UFO_GetByIDX(cgi->XML_GetInt(aimedAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, 0));
			else
				projectile->aimedAircraft = AIR_AircraftGetFromIDX(cgi->XML_GetInt(aimedAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, AIRCRAFT_INVALID));
		} else {
			projectile->aimedAircraft = nullptr;
		}
	}
	ccs.numProjectiles = i;

	return true;
}
Esempio n. 6
0
/**
 * @brief Unloads transfer cargo when finishing the transfer or destroys it when no buildings/base.
 * @param[in,out] destination The destination base - might be NULL in case the base
 * is already destroyed
 * @param[in] transfer Pointer to transfer in ccs.transfers.
 * @param[in] success True if the transfer reaches dest base, false if the base got destroyed.
 * @sa TR_TransferEnd
 */
static void TR_EmptyTransferCargo (base_t *destination, transfer_t *transfer, qboolean success)
{
	assert(transfer);

	if (transfer->hasItems && success) {	/* Items. */
		const objDef_t *od = INVSH_GetItemByID(ANTIMATTER_TECH_ID);
		int i;

		/* antimatter */
		if (transfer->itemAmount[od->idx] > 0) {
			if (B_GetBuildingStatus(destination, B_ANTIMATTER)) {
				B_ManageAntimatter(destination, transfer->itemAmount[od->idx], qtrue);
			} else {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Antimatter Storage, antimatter are removed!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL);
			}
		}
		/* items */
		for (i = 0; i < csi.numODs; i++) {
			od = INVSH_GetItemByIDX(i);

			if (transfer->itemAmount[od->idx] <= 0)
				continue;
			if (!B_ItemIsStoredInBaseStorage(od))
				continue;
			if (!B_GetBuildingStatus(destination, B_STORAGE)) {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Storage, items are removed!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL);
				break;
			}
			B_UpdateStorageAndCapacity(destination, od, transfer->itemAmount[od->idx], qfalse, qtrue);
		}
	}

	if (transfer->hasEmployees && transfer->srcBase) {	/* Employees. (cannot come from a mission) */
		if (!success || !B_GetBuildingStatus(destination, B_QUARTERS)) {	/* Employees will be unhired. */
			employeeType_t i;
			if (success) {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Living Quarters, employees got unhired!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL);
			}
			for (i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
				employee_t *employee;
				TR_ForeachEmployee(employee, transfer, i) {
					employee->baseHired = transfer->srcBase;	/* Restore back the original baseid. */
					employee->transfer = qfalse;
					E_UnhireEmployee(employee);
				}
			}
		} else {
Esempio n. 7
0
/**
 * @brief Change UFOpaedia article when clicking on the name of associated ammo or weapon
 */
static void UP_ResearchedLinkClick_f (void)
{
	const objDef_t* od;

	if (!upCurrentTech) /* if called from console */
		return;

	od = INVSH_GetItemByID(upCurrentTech->provides);
	assert(od);

	if (od->isAmmo()) {
		const technology_t* t = RS_GetTechForItem(od->weapons[0]);
		if (UP_TechGetsDisplayed(t))
			UP_OpenWith(t->id);
	} else if (od->weapon && od->isReloadable()) {
		const technology_t* t = RS_GetTechForItem(od->ammos[0]);
		if (UP_TechGetsDisplayed(t))
			UP_OpenWith(t->id);
	}
}
Esempio n. 8
0
/**
 * @brief Unloads transfer cargo when finishing the transfer or destroys it when no buildings/base.
 * @param[in,out] destination The destination base - might be nullptr in case the base
 * is already destroyed
 * @param[in] transfer Pointer to transfer in ccs.transfers.
 * @param[in] success True if the transfer reaches dest base, false if the base got destroyed.
 * @sa TR_TransferEnd
 */
static void TR_EmptyTransferCargo (base_t* destination, transfer_t* transfer, bool success)
{
	assert(transfer);

	if (transfer->hasItems && success) {	/* Items. */
		const objDef_t* od = INVSH_GetItemByID(ANTIMATTER_ITEM_ID);
		int i;

		/* antimatter */
		if (transfer->itemAmount[od->idx] > 0) {
			if (B_GetBuildingStatus(destination, B_ANTIMATTER)) {
				B_ManageAntimatter(destination, transfer->itemAmount[od->idx], true);
			} else {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Antimatter Storage, antimatter are removed!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, MSG_TRANSFERFINISHED);
			}
		}
		/* items */
		for (i = 0; i < cgi->csi->numODs; i++) {
			od = INVSH_GetItemByIDX(i);

			if (transfer->itemAmount[od->idx] <= 0)
				continue;
			if (!B_ItemIsStoredInBaseStorage(od))
				continue;
			B_AddToStorage(destination, od, transfer->itemAmount[od->idx]);
		}
	}

	if (transfer->hasEmployees && transfer->srcBase) {	/* Employees. (cannot come from a mission) */
		if (!success) {	/* Employees will be unhired. */
			for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
				const employeeType_t type = (employeeType_t)i;
				TR_ForeachEmployee(employee, transfer, type) {
					employee->baseHired = transfer->srcBase;	/* Restore back the original baseid. */
					employee->transfer = false;
					employee->unhire();
				}
			}
		} else {
			for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
Esempio n. 9
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];
}
/**
 * @brief Update the list of item you can choose
 * @param[in] slot Pointer to aircraftSlot where items can be equiped
 */
static void AIM_UpdateAircraftItemList (const aircraftSlot_t *slot)
{
	linkedList_t *amountList = NULL;
	technology_t **techList;
	technology_t **currentTech;
	const base_t *base = slot->aircraft->homebase;
	int count = 0;
	uiNode_t *AIM_items = NULL;

	/* Add all items corresponding to airequipID to list */
	techList = AII_GetCraftitemTechsByType(airequipID);

	/* Count only those which are researched to buffer */
	currentTech = techList;
	while (*currentTech) {
		if (AIM_CrafttypeFilter(base, airequipID, *currentTech))
			count++;
		currentTech++;
	}

	/* List only those which are researched to buffer */
	currentTech = techList;
	while (*currentTech) {
		if (AIM_CrafttypeFilter(base, airequipID, *currentTech)) {
			uiNode_t *option;
			const objDef_t *item = INVSH_GetItemByID((*currentTech)->provides);
			const int amount = B_ItemInBase(item, base);

			LIST_AddString(&amountList, va("%d", amount));
			option = cgi->UI_AddOption(&AIM_items, (*currentTech)->name, _((*currentTech)->name), va("%d", (*currentTech)->idx));
			if (!AIM_SelectableCraftItem(slot, *currentTech))
				option->disabled = true;
		}
		currentTech++;
	}

	cgi->UI_RegisterOption(TEXT_LIST, AIM_items);
	cgi->UI_RegisterLinkedListText(TEXT_LIST2, amountList);
}
Esempio n. 11
0
/**
 * @brief Load callback for savegames
 * @param[in] parent XML Node structure, where we get the information from
 * @sa BS_Save
 * @sa SAV_GameLoad
 */
bool BS_LoadXML (xmlNode_t* parent)
{
	xmlNode_t* node, *snode;
	market_t* market = BS_GetMarket();

	node = cgi->XML_GetNode(parent, SAVE_MARKET_MARKET);
	if (!node)
		return false;

	for (snode = cgi->XML_GetNode(node, SAVE_MARKET_ITEM); snode; snode = cgi->XML_GetNextNode(snode, node, SAVE_MARKET_ITEM)) {
		const char* s = cgi->XML_GetString(snode, SAVE_MARKET_ID);
		const objDef_t* od = INVSH_GetItemByID(s);

		if (!od) {
			Com_Printf("BS_LoadXML: Could not find item '%s'\n", s);
			continue;
		}

		market->numItems[od->idx] = cgi->XML_GetInt(snode, SAVE_MARKET_NUM, 0);
		market->bidItems[od->idx] = cgi->XML_GetInt(snode, SAVE_MARKET_BID, 0);
		market->askItems[od->idx] = cgi->XML_GetInt(snode, SAVE_MARKET_ASK, 0);
		market->currentEvolutionItems[od->idx] = cgi->XML_GetDouble(snode, SAVE_MARKET_EVO, 0.0);
		market->autosell[od->idx] = cgi->XML_GetBool(snode, SAVE_MARKET_AUTOSELL, false);
	}
	for (snode = cgi->XML_GetNode(node, SAVE_MARKET_AIRCRAFT); snode; snode = cgi->XML_GetNextNode(snode, node, SAVE_MARKET_AIRCRAFT)) {
		const char* s = cgi->XML_GetString(snode, SAVE_MARKET_ID);
		const humanAircraftType_t type = cgi->Com_DropShipShortNameToID(s);

		market->numAircraft[type] = cgi->XML_GetInt(snode, SAVE_MARKET_NUM, 0);
		market->bidAircraft[type] = cgi->XML_GetInt(snode, SAVE_MARKET_BID, 0);
		market->askAircraft[type] = cgi->XML_GetInt(snode, SAVE_MARKET_ASK, 0);
		market->currentEvolutionAircraft[type] = cgi->XML_GetDouble(snode, SAVE_MARKET_EVO, 0.0);
	}

	return true;
}
Esempio n. 12
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");
	}
}
Esempio n. 13
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);
}
Esempio n. 14
0
/**
 * @brief add item to a base defence slot (installation too)
 */
static void BDEF_AddItem_f (void)
{
	aircraftSlot_t* slot;
	installation_t* installation = INS_GetCurrentSelectedInstallation();
	base_t* base = B_GetCurrentSelectedBase();
	technology_t** list;
	technology_t* itemTech = nullptr;
	aircraftItemType_t bdefType;
	int slotIDX;

	if ((!base && !installation) || (base && installation)) {
		Com_Printf("Exiting early base and installation both true or both false\n");
		return;
	}

	if (cgi->Cmd_Argc() < 3) {
		Com_Printf("Usage: %s <type> <slotIDX>\n", cgi->Cmd_Argv(0));
		return;
	}

	bdefType = BDEF_GetItemTypeFromID(cgi->Cmd_Argv(1));
	slotIDX = atoi(cgi->Cmd_Argv(2));

	if (bdefType == MAX_ACITEMS) {
		Com_Printf("BDEF_AddItem_f: Invalid defence type.\n");
		return;
	}

	if (slotIDX < 0) {
		return;
	} else {
		int maxWeapon;
		if (base)
			maxWeapon = (bdefType == AC_ITEM_BASE_MISSILE) ? base->numActiveBatteries : base->numActiveLasers;
		else
			maxWeapon = installation->numBatteries;
		if (slotIDX >= maxWeapon)
			return;
	}

	slot = (installation) ? BDEF_GetInstallationSlotByIDX(installation, bdefType, slotIDX) : BDEF_GetBaseSlotByIDX(base, bdefType, slotIDX);

	if (!slot) {
		Com_Printf("BDEF_AddItem_f: Invalid slot.\n");
		return;
	}

	list = AII_GetCraftitemTechsByType(bdefType);
	while (*list) {
		if (AIM_SelectableCraftItem(slot, *list)) {
			itemTech = *list;
			break;
		}
		list++;
	}

	if (!itemTech)
		return;

	if (!slot->nextItem) {
		/* we add the weapon, shield, item, or base defence if slot is free or the installation of
		 * current item just began */
		if (!slot->item || (slot->item && slot->installationTime == slot->item->craftitem.installationTime)) {
			AII_RemoveItemFromSlot(base, slot, false);
			AII_AddItemToSlot(base, itemTech, slot, false); /* Aircraft stats are updated below */
			AII_AutoAddAmmo(slot);
		} else if (slot->item == INVSH_GetItemByID(itemTech->provides)) {
			/* the added item is the same than the one in current slot */
			if (slot->installationTime == -slot->item->craftitem.installationTime) {
				/* player changed his mind: he just want to re-add the item he just removed */
				slot->installationTime = 0;
			} else if (!slot->installationTime) {
				/* player try to add a weapon he already have: just skip */
			}
		} else {
			/* We start removing current item in slot, and the selected item will be installed afterwards */
			slot->installationTime = -slot->item->craftitem.installationTime;
			AII_AddItemToSlot(base, itemTech, slot, true);
			AII_AutoAddAmmo(slot);
		}
	} else {
		/* remove weapon and ammo of next item */
		AII_RemoveItemFromSlot(base, slot, false);
		AII_AddItemToSlot(base, itemTech, slot, true);
		AII_AutoAddAmmo(slot);
	}

	/* Reinit menu */
	cgi->Cmd_ExecuteString("basedef_updatemenu %s", BDEF_GetIDFromItemType(slot->type));
}
Esempio n. 15
0
/**
 * @brief Load callback for xml savegames
 * @param[in] p XML Node structure, where we get the information from
 * @sa PR_SaveXML
 * @sa SAV_GameLoadXML
 */
bool PR_LoadXML (xmlNode_t* p)
{
	xmlNode_t* node = cgi->XML_GetNode(p, SAVE_PRODUCE_PRODUCTION);

	for (xmlNode_t* snode = cgi->XML_GetNode(node, SAVE_PRODUCE_QUEUE); snode;
			snode = cgi->XML_GetNextNode(snode, node, SAVE_PRODUCE_QUEUE)) {
		xmlNode_t* ssnode;
		const int baseIDX = cgi->XML_GetInt(snode, SAVE_PRODUCE_QUEUEIDX, MAX_BASES);
		base_t* base = B_GetBaseByIDX(baseIDX);
		production_queue_t* pq;

		if (base == nullptr) {
			Com_Printf("Invalid production queue index %i\n", baseIDX);
			continue;
		}

		pq = PR_GetProductionForBase(base);

		for (ssnode = cgi->XML_GetNode(snode, SAVE_PRODUCE_ITEM); pq->numItems < MAX_PRODUCTIONS && ssnode;
				ssnode = cgi->XML_GetNextNode(ssnode, snode, SAVE_PRODUCE_ITEM)) {
			const char* s1 = cgi->XML_GetString(ssnode, SAVE_PRODUCE_ITEMID);
			production_t* prod = &pq->items[pq->numItems];

			prod->idx = pq->numItems;
			prod->amount = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_AMOUNT, 0);
			prod->frame = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_PROGRESS, 0);

			/* amount */
			if (prod->amount <= 0) {
				Com_Printf("PR_LoadXML: Production with amount <= 0 dropped (baseidx=%i, production idx=%i).\n",
						baseIDX, pq->numItems);
				continue;
			}
			/* item */
			if (s1[0] != '\0')
				PR_SetData(&prod->data, PRODUCTION_TYPE_ITEM, INVSH_GetItemByID(s1));
			/* UFO */
			const int ufoIDX = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_UFOIDX, -1);
			if (ufoIDX != -1) {
				storedUFO_t* ufo = US_GetStoredUFOByIDX(ufoIDX);

				if (!ufo) {
					Com_Printf("PR_LoadXML: Could not find ufo idx: %i\n", ufoIDX);
					continue;
				}

				PR_SetData(&prod->data, PRODUCTION_TYPE_DISASSEMBLY, ufo);
				PR_SetUFODisassembly(prod);
			}
			/* aircraft */
			const char* s2 = cgi->XML_GetString(ssnode, SAVE_PRODUCE_AIRCRAFTID);
			if (s2[0] != '\0')
				PR_SetData(&prod->data, PRODUCTION_TYPE_AIRCRAFT, AIR_GetAircraft(s2));

			if (!PR_IsDataValid(&prod->data)) {
				Com_Printf("PR_LoadXML: Production is not an item an aircraft nor a disassembly\n");
				continue;
			}

			pq->numItems++;
		}
	}
	return true;
}
Esempio n. 16
0
/**
 * @brief Parses one "components" entry in a .ufo file and writes it into the next free entry in xxxxxxxx (components_t).
 * @param[in] name The unique id of a components_t array entry.
 * @param[in] text the whole following text after the "components" definition.
 * @sa CP_ParseScriptFirst
 */
static void CP_ParseComponents (const char *name, const char **text)
{
	components_t *comp;
	const char *errhead = "CP_ParseComponents: unexpected end of file.";
	const char *token;

	/* get body */
	token = Com_Parse(text);
	if (!*text || *token != '{') {
		Com_Printf("CP_ParseComponents: \"%s\" components def without body ignored.\n", name);
		return;
	}
	if (ccs.numComponents >= MAX_ASSEMBLIES) {
		Com_Printf("CP_ParseComponents: too many technology entries. limit is %i.\n", MAX_ASSEMBLIES);
		return;
	}

	/* New components-entry (next free entry in global comp-list) */
	comp = &ccs.components[ccs.numComponents];
	ccs.numComponents++;

	OBJZERO(*comp);

	/* set standard values */
	Q_strncpyz(comp->assemblyId, name, sizeof(comp->assemblyId));
	comp->assemblyItem = INVSH_GetItemByIDSilent(comp->assemblyId);
	if (comp->assemblyItem)
		Com_DPrintf(DEBUG_CLIENT, "CP_ParseComponents: linked item: %s with components: %s\n", name, comp->assemblyId);

	do {
		/* get the name type */
		token = Com_EParse(text, errhead, name);
		if (!*text)
			break;
		if (*token == '}')
			break;

		/* get values */
		if (Q_streq(token, "item")) {
			/* Defines what items need to be collected for this item to be researchable. */
			if (comp->numItemtypes < MAX_COMP) {
				/* Parse item name */
				token = Com_Parse(text);

				comp->items[comp->numItemtypes] = INVSH_GetItemByID(token);	/* item id -> item pointer */

				/* Parse number of items. */
				token = Com_Parse(text);
				comp->itemAmount[comp->numItemtypes] = atoi(token);
				token = Com_Parse(text);
				/* If itemcount needs to be scaled */
				if (token[0] == '%')
					comp->itemAmount2[comp->numItemtypes] = COMP_ITEMCOUNT_SCALED;
				else
					comp->itemAmount2[comp->numItemtypes] = atoi(token);

				/** @todo Set item links to NONE if needed */
				/* comp->item_idx[comp->numItemtypes] = xxx */

				comp->numItemtypes++;
			} else {
				Com_Printf("CP_ParseComponents: \"%s\" Too many 'items' defined. Limit is %i - ignored.\n", name, MAX_COMP);
			}
		} else if (Q_streq(token, "time")) {
			/* Defines how long disassembly lasts. */
			token = Com_Parse(text);
			comp->time = atoi(token);
		} else {
			Com_Printf("CP_ParseComponents: Error in \"%s\" - unknown token: \"%s\".\n", name, token);
		}
	} while (*text);
}
/**
 * @brief Add selected item to current zone.
 * @note Called from airequip menu
 * @sa aircraftItemType_t
 */
static void AIM_AircraftEquipAddItem_f (void)
{
	int zone;
	aircraftSlot_t *slot;
	aircraft_t *aircraft = NULL;
	base_t *base = B_GetCurrentSelectedBase();

	zone = (airequipID == AC_ITEM_AMMO) ? 2 : 1;

	/* proceed only if an item has been selected */
	if (!aimSelectedTechnology)
		return;

	assert(base);
	aircraft = base->aircraftCurrent;
	assert(aircraft);
	base = aircraft->homebase;	/* we need to know where items will be removed */
	slot = AII_SelectAircraftSlot(aircraft, airequipID);

	/* the clicked button doesn't correspond to the selected zone */
	if (zone != airequipSelectedZone)
		return;

	/* check if the zone exists */
	if (zone >= ZONE_MAX)
		return;

	/* update the new item to slot */

	switch (zone) {
	case ZONE_MAIN:
		if (!slot->nextItem) {
			/* we add the weapon, shield, item if slot is free or the installation of current item just began */
			if (!slot->item || (slot->item && slot->installationTime == slot->item->craftitem.installationTime)) {
				AII_RemoveItemFromSlot(base, slot, false);
				AII_AddItemToSlot(base, aimSelectedTechnology, slot, false); /* Aircraft stats are updated below */
				AII_AutoAddAmmo(slot);
				break;
			} else if (slot->item == INVSH_GetItemByID(aimSelectedTechnology->provides)) {
				/* the added item is the same than the one in current slot */
				if (slot->installationTime == -slot->item->craftitem.installationTime) {
					/* player changed his mind: he just want to re-add the item he just removed */
					slot->installationTime = 0;
					break;
				} else if (!slot->installationTime) {
					/* player try to add a weapon he already have: just skip */
					return;
				}
			} else {
				/* We start removing current item in slot, and the selected item will be installed afterwards */
				slot->installationTime = -slot->item->craftitem.installationTime;
				/* more below */
			}
		} else {
			/* remove weapon and ammo of next item */
			AII_RemoveNextItemFromSlot(base, slot, false);
			/* more below */
		}

		/* we change the weapon, shield, item, or base defence that will be installed AFTER the removal
		 * of the one in the slot atm */
		AII_AddItemToSlot(base, aimSelectedTechnology, slot, true);
		AII_AutoAddAmmo(slot);
		break;
	case ZONE_AMMO:
		/* we can change ammo only if the selected item is an ammo (for weapon or base defence system) */
		if (airequipID >= AC_ITEM_AMMO) {
			AII_AddAmmoToSlot(base, aimSelectedTechnology, slot);
		}
		break;
	default:
		/* Zone higher than ZONE_AMMO shouldn't exist */
		return;
	}

	/* Update the values of aircraft stats (just in case an item has an installationTime of 0) */
	AII_UpdateAircraftStats(aircraft);

	AIM_AircraftEquipMenuUpdate();
}
/**
 * @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;
}
Esempio n. 19
0
/**
 * @brief Buy/Sell item/aircraft/ugv on the market
 */
static void BS_Buy_f (void)
{
	const char* itemid;
	int count;
	base_t* base = B_GetCurrentSelectedBase();
	const aircraft_t* aircraft;
	const ugv_t* ugv;
	const objDef_t* od;

	if (cgi->Cmd_Argc() < 2) {
		cgi->Com_Printf("Usage: %s <item-id> <count> [base-idx] \nNegative count means selling. If base index is omitted buys on the currently selected base.\n",
				cgi->Cmd_Argv(0));
		return;
	}

	itemid = cgi->Cmd_Argv(1);
	count = atoi(cgi->Cmd_Argv(2));

	if (cgi->Cmd_Argc() >= 4)
		base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(3)));

	if (char const* const rest = Q_strstart(itemid, "aircraft_")) {
		/* aircraft sell - with aircraft golbal idx */
		int idx = atoi(rest);
		aircraft_t* aircraft = AIR_AircraftGetFromIDX(idx);

		if (!aircraft) {
			cgi->Com_Printf("Invalid aircraft index!\n");
			return;
		}
		AIR_RemoveEmployees(*aircraft);
		BS_SellAircraft(aircraft);
		return;
	}

	if (char const* const rest = Q_strstart(itemid, "ugv-")) {
		/* ugv sell - with unique character number index */
		int ucn = atoi(rest);
		Employee* robot = E_GetEmployeeByTypeFromChrUCN(EMPL_ROBOT, ucn);

		if (!robot) {
			cgi->Com_Printf("Invalid UCN for UGV!\n");
			return;
		}

		BS_SellUGV(robot);
		return;
	}

	if (!base) {
		cgi->Com_Printf("No/invalid base selected.\n");
		return;
	}

	aircraft = AIR_GetAircraftSilent(itemid);
	if (aircraft) {
		if (!B_GetBuildingStatus(base, B_COMMAND)) {
			CP_Popup(_("Note"), _("No Command Centre in this base.\nHangars are not functional.\n"));
			return;
		}
		/* We cannot buy aircraft if there is no power in our base. */
		if (!B_GetBuildingStatus(base, B_POWER)) {
			CP_Popup(_("Note"), _("No power supplies in this base.\nHangars are not functional."));
			return;
		}
		/* We cannot buy aircraft without any hangar. */
		if (!AIR_AircraftAllowed(base)) {
			CP_Popup(_("Note"), _("Build a hangar first."));
			return;
		}
		/* Check free space in hangars. */
		if (CAP_GetFreeCapacity(base, AIR_GetHangarCapacityType(aircraft)) <= 0) {
			CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough space in hangars.\n"));
			return;
		}

		if (ccs.credits < BS_GetAircraftBuyingPrice(aircraft)) {
			CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough credits.\n"));
			return;
		}

		BS_BuyAircraft(aircraft, base);
		return;
	}

	ugv = cgi->Com_GetUGVByIDSilent(itemid);
	if (ugv) {
		const objDef_t* ugvWeapon = INVSH_GetItemByID(ugv->weapon);
		if (!ugvWeapon)
			cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get weapon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id);

		if (E_CountUnhiredRobotsByType(ugv) < 1)
			return;
		if (ccs.eMarket.numItems[ugvWeapon->idx] < 1)
			return;

		if (ccs.credits < ugv->price) {
			CP_Popup(_("Not enough money"), _("You cannot buy this item as you don't have enough credits."));
			return;
		}

		if (CAP_GetFreeCapacity(base, CAP_ITEMS) < UGV_SIZE + ugvWeapon->size) {
			CP_Popup(_("Not enough storage space"), _("You cannot buy this item.\nNot enough space in storage.\nBuild more storage facilities."));
			return;
		}

		BS_BuyUGV(ugv, base);
		return;
	}

	if (count == 0) {
		cgi->Com_Printf("Invalid number of items to buy/sell: %s\n", cgi->Cmd_Argv(2));
		return;
	}

	/* item */
	od = INVSH_GetItemByID(cgi->Cmd_Argv(1));
	if (od) {
		if (!BS_IsOnMarket(od))
			return;

		if (count > 0) {
			/* buy */
			const int price = BS_GetItemBuyingPrice(od);
			count = std::min(count, BS_GetItemOnMarket(od));

			/* no items available on market */
			if (count <= 0)
				return;

			if (price <= 0) {
				cgi->Com_Printf("Item on market with invalid buying price: %s (%d)\n", od->id, BS_GetItemBuyingPrice(od));
				return;
			}
			/** @todo warn if player can buy less item due to available credits? */
			count = std::min(count, ccs.credits / price);
			/* not enough money for a single item */
			if (count <= 0) {
				CP_Popup(_("Not enough money"), _("You cannot buy this item as you don't have enough credits."));
				return;
			}

			if (od->size <= 0) {
				cgi->Com_Printf("Item on market with invalid size: %s (%d)\n", od->id, od->size);
				return;
			}
			count = std::min(count, CAP_GetFreeCapacity(base, CAP_ITEMS) / od->size);
			if (count <= 0) {
				CP_Popup(_("Not enough storage space"), _("You cannot buy this item.\nNot enough space in storage.\nBuild more storage facilities."));
				return;
			}

			BS_BuyItem(od, base, count);
		} else {
			/* sell */
			count = std::min(-1 * count, B_ItemInBase(od, base));
			/* no items in storage */
			if (count <= 0)
				return;
			BS_SellItem(od, base, count);
		}
		return;
	}
	cgi->Com_Printf("Invalid item ID\n");
}
Esempio n. 20
0
/**
 * @brief Show information about item/aircaft/ugv in the market
 */
static void BS_ShowInfo_f (void)
{
	const char* itemid;
	const aircraft_t* aircraft;
	const ugv_t* ugv;
	const objDef_t* od;

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

	itemid = cgi->Cmd_Argv(1);

	if (char const* const rest = Q_strstart(itemid, "aircraft_")) {
		/* PHALANX aircraft - with aircraft golbal idx */
		int idx = atoi(rest);
		aircraft = AIR_AircraftGetFromIDX(idx);

		if (!aircraft) {
			cgi->Com_Printf("Invalid aircraft index!\n");
			return;
		}
		/** @todo show specialized info about PHALANX aircraft */
		BS_MarketAircraftDescription(aircraft->tpl);
		return;
	}

	if (char const* const rest = Q_strstart(itemid, "ugv-")) {
		/* PHALANX ugv - with unique character number index */
		int ucn = atoi(rest);
		Employee* robot = E_GetEmployeeByTypeFromChrUCN(EMPL_ROBOT, ucn);

		if (!robot) {
			cgi->Com_Printf("Invalid UCN for UGV!\n");
			return;
		}

		/** @todo show specialized info about PHLANX UGVs */
		UP_UGVDescription(robot->getUGV());
		return;
	}

	aircraft = AIR_GetAircraftSilent(itemid);
	if (aircraft) {
		BS_MarketAircraftDescription(aircraft->tpl);
		return;
	}

	ugv = cgi->Com_GetUGVByIDSilent(itemid);
	if (ugv) {
		UP_UGVDescription(ugv);
		return;
	}

	/* item */
	od = INVSH_GetItemByID(cgi->Cmd_Argv(1));
	if (od) {
		if (!BS_IsOnMarket(od))
			return;

		if (od->craftitem.type != MAX_ACITEMS)
			UP_AircraftItemDescription(od);
		else
			cgi->INV_ItemDescription(od);
		return;
	}
	cgi->Com_Printf("Invalid item ID\n");
}
Esempio n. 21
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;
	}