Exemple #1
0
/**
 * @brief Make sure equipment definitions used to generate teams are proper.
 * @note Check that the sum of all probabilities is smaller or equal to 100 for a weapon type.
 * @sa INVSH_EquipActor
 */
static bool INV_EquipmentDefSanityCheck (void)
{
	int i, j;
	int sum;
	bool result = true;

	for (i = 0; i < csi.numEDs; i++) {
		const equipDef_t *const ed = &csi.eds[i];
		/* only check definitions used for generating teams */
		if (!Q_strstart(ed->id, "alien") && !Q_strstart(ed->id, "phalanx"))
			continue;

		/* Check primary */
		sum = 0;
		for (j = 0; j < csi.numODs; j++) {
			const objDef_t *const obj = INVSH_GetItemByIDX(j);
			if (obj->weapon && obj->fireTwoHanded
			 && (INV_ItemMatchesFilter(obj, FILTER_S_PRIMARY) || INV_ItemMatchesFilter(obj, FILTER_S_HEAVY)))
				sum += ed->numItems[j];
		}
		if (sum > 100) {
			Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for primary weapons greater than 100\n", ed->id);
			result = false;
		}

		/* Check secondary */
		sum = 0;
		for (j = 0; j < csi.numODs; j++) {
			const objDef_t *const obj = INVSH_GetItemByIDX(j);
			if (obj->weapon && obj->reload && !obj->deplete && INV_ItemMatchesFilter(obj, FILTER_S_SECONDARY))
				sum += ed->numItems[j];
		}
		if (sum > 100) {
			Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for secondary weapons greater than 100\n", ed->id);
			result = false;
		}

		/* Check armour */
		sum = 0;
		for (j = 0; j < csi.numODs; j++) {
			const objDef_t *const obj = INVSH_GetItemByIDX(j);
			if (INV_ItemMatchesFilter(obj, FILTER_S_ARMOUR))
				sum += ed->numItems[j];
		}
		if (sum > 100) {
			Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for armours greater than 100\n", ed->id);
			result = false;
		}

		/* Don't check misc: the total probability can be greater than 100 */
	}

	return result;
}
/**
 * @brief Compute the next itemID
 * @note If something found, item type can be find with iterator->itemID
 * @note If item is available into the container iterator->itemFound point to this element
 * @note If nothing found (no next element) then iterator->itemID >= csi.numODs
 */
static void UI_ContainerItemIteratorNext (containerItemIterator_t* iterator)
{
	assert(iterator->groupSteps[iterator->groupID] != CII_END);

	/* iterate each groups */
	for (; iterator->groupSteps[iterator->groupID] != CII_END; iterator->groupID++) {
		int filter = iterator->groupSteps[iterator->groupID];
		/* next */
		iterator->itemID++;

		/* iterate all item type*/
		for (;iterator->itemID < csi.numODs; iterator->itemID++) {
			const objDef_t* obj = INVSH_GetItemByIDX(iterator->itemID);

			/* gameplay filter */
			if (!GAME_ItemIsUseable(obj))
				continue;

			/* type filter */
			/** @todo not sure its the right check */
			const bool isArmour = obj->isArmour();
			const bool isAmmo = obj->numWeapons != 0 && obj->isAmmo();
			const bool isWeapon = obj->weapon || obj->isMisc || isArmour;
			const bool isImplant = obj->implant;

			if ((filter & CII_WEAPONONLY) && !isWeapon)
				continue;
			if ((filter & CII_AMMOONLY) && !isAmmo)
				continue;
			if ((filter & CII_IMPLANTONLY) && !isImplant)
				continue;
			if (!INV_ItemMatchesFilter(obj, iterator->filterEquipType))
				continue;

			/* exists in inventory filter */
			iterator->itemFound = UI_ContainerNodeGetExistingItem(iterator->node, obj, iterator->filterEquipType);
			if ((filter & CII_AVAILABLEONLY) && iterator->itemFound == nullptr)
				continue;
			if ((filter & CII_NOTAVAILABLEONLY) && iterator->itemFound != nullptr)
				continue;

			/* we found something */
			return;
		}

		/* can we search into another group? */
		if (iterator->groupSteps[iterator->groupID + 1] != CII_END)
			iterator->itemID = -1;
	}

	/* clean up */
	iterator->itemFound = nullptr;
}
/**
 * @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);
		}
	}
}
Exemple #4
0
/**
 * @brief Searches if there is an item at location (x/y) in a scrollable container. You can also provide an item to search for directly (x/y is ignored in that case).
 * @note x = x-th item in a row, y = row. i.e. x/y does not equal the "grid" coordinates as used in those containers.
 * @param[in] i Pointer to the inventory where we will search.
 * @param[in] container Container in the inventory.
 * @param[in] x/y Position in the scrollable container that you want to check. Ignored if "item" is set.
 * @param[in] item The item to search. Will ignore "x" and "y" if set, it'll also search invisible items.
 * @param[in] filterType Enum definition of type (types of items for filtering purposes).
 * @return @c invList_t Pointer to the invList_t/item that is located at x/y or equals "item".
 * @sa INVSH_SearchInInventory
 */
invList_t *INV_SearchInInventoryWithFilter (const inventory_t* const i, const invDef_t * container, const objDef_t *item,  const itemFilterTypes_t filterType)
{
	invList_t *ic;

	if (i == NULL)
		return NULL;

	if (item == NULL)
		return NULL;

	for (ic = i->c[container->id]; ic; ic = ic->next) {
		/* Search only in the items that could get displayed. */
		if (ic && ic->item.item && (filterType == MAX_FILTERTYPES || INV_ItemMatchesFilter(ic->item.item, filterType))) {
			/* We search _everything_, no matter what location it is (i.e. x/y are ignored). */
			if (item == ic->item.item)
				return ic;
		}
	}

	/* No item with these coordinates (or matching item) found. */
	return NULL;
}
Exemple #5
0
/**
 * @brief Searches if there is an item at location (x/y) in a scrollable container. You can also provide an item to search for directly (x/y is ignored in that case).
 * @note x = x-th item in a row, y = row. i.e. x/y does not equal the "grid" coordinates as used in those containers.
 * @param[in] inv Pointer to the inventory where we will search.
 * @param[in] container Container in the inventory.
 * @param[in] itemType The item to search. Will ignore "x" and "y" if set, it'll also search invisible items.
 * @param[in] filterType Enum definition of type (types of items for filtering purposes).
 * @return @c invList_t Pointer to the invList_t/item that is located at x/y or equals "item".
 * @sa inventory_t::getItemAtPos
 */
invList_t *INV_SearchInInventoryWithFilter (const inventory_t* const inv, const invDef_t *container, const objDef_t *itemType,  const itemFilterTypes_t filterType)
{
	invList_t *ic;

	if (inv == nullptr)
		return nullptr;

	if (itemType == nullptr)
		return nullptr;

	for (ic = inv->getContainer3(container->id); ic; ic = ic->getNext()) {
		/* Search only in the items that could get displayed. */
		if (ic && ic->def() && (filterType == MAX_FILTERTYPES || INV_ItemMatchesFilter(ic->def(), filterType))) {
			/* We search _everything_, no matter what location it is (i.e. x/y are ignored). */
			if (itemType == ic->def())
				return ic;
		}
	}

	/* No item with these coordinates (or matching item) found. */
	return nullptr;
}
/**
 * @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);
}
Exemple #7
0
/**
 * @brief Checks if the given object/item matched the given filter type.
 * @param[in] obj A pointer to an objDef_t item.
 * @param[in] filterType Filter type to check against.
 * @return @c true if obj is in filterType
 */
bool INV_ItemMatchesFilter (const objDef_t *obj, const itemFilterTypes_t filterType)
{
	int i;

	if (!obj)
		return false;

	switch (filterType) {
	case FILTER_S_PRIMARY:
		if (obj->isPrimary && !obj->isHeavy)
			return true;

		/* Check if one of the items that uses this ammo matches this filter type. */
		for (i = 0; i < obj->numWeapons; i++) {
			const objDef_t *weapon = obj->weapons[i];
			if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType))
				return true;
		}
		break;

	case FILTER_S_SECONDARY:
		if (obj->isSecondary && !obj->isHeavy)
			return true;

		/* Check if one of the items that uses this ammo matches this filter type. */
		for (i = 0; i < obj->numWeapons; i++) {
			const objDef_t *weapon = obj->weapons[i];
			if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType))
				return true;
		}
		break;

	case FILTER_S_HEAVY:
		if (obj->isHeavy)
			return true;

		/* Check if one of the items that uses this ammo matches this filter type. */
		for (i = 0; i < obj->numWeapons; i++) {
			const objDef_t *weapon = obj->weapons[i];
			if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType))
				return true;
		}
		break;

	case FILTER_S_ARMOUR:
		return INV_IsArmour(obj);

	case FILTER_S_MISC:
		return obj->isMisc;

	case FILTER_CRAFTITEM:
		/** @todo Should we handle FILTER_AIRCRAFT here as well? */
		return INV_IsCraftItem(obj);

	case FILTER_UGVITEM:
		return obj->isUGVitem;

	case FILTER_DUMMY:
		return obj->isDummy;

	case FILTER_AIRCRAFT:
		return Q_streq(obj->type, "aircraft");

	case FILTER_DISASSEMBLY:
		/** @todo I guess we should search for components matching this item here. */
		break;

	case MAX_SOLDIER_FILTERTYPES:
	case MAX_FILTERTYPES:
	case FILTER_ENSURE_32BIT:
		Com_Printf("INV_ItemMatchesFilter: Unknown filter type for items: %i\n", filterType);
		break;
	}

	/* The given filter type is unknown. */
	return false;
}
/**
 * @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) {
		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) {
		Com_Printf("No/invalid base selected.\n");
		return;
	}

	type = 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->ugv;
			const technology_t* tech = RS_GetTechByProvided(ugv->id);

			if (!E_IsInBase(robot, base))
				continue;

			cgi->UI_ExecuteConfunc("ui_market_add \"ugv-%d\" \"%s\" 1 0 0 %d - \"%s\"", robot->chr.ucn, _(tech->name), ugv->price, E_IsAwayFromBase(robot) ? _("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 */
	case FILTER_S_PRIMARY:
	case FILTER_S_SECONDARY:
	case FILTER_S_HEAVY:
	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 && !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;
			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;
	}