Currently OXCE+ allows items to be restricted to a list of supported inventory slots but doesn't allow the inventory slot to be restricted to supported items. For example, as a ruleset moder I could make it so that STR_RIFLE_CLIP can only go in slot STR_CLIP_HOLDER, but short of adding an applicability list to every equipable item in the game I can't make it so that only STR_RIFLE_CLIP, or only clips, can go in STR_CLIP_HOLDER. Right now we want this feature for Piratez to add a dedicated utility items slot without having to add a list of all other slots to every non-utility item.
I want to add a property "PlacementRestrictionLevel" to inventory slots that, when set >1, causes applicability to be enforced for all items. By default slots would have restriction level 1 and only enforce applicability for items that have a non-null applicability list. PlacementRestrictionLevel: 0 (or any slot named "STR_GROUND") would ignore applicability entirely. Useful for a backpack maybe.
First we have to add the property and a getter in Mod/RuleInventory.cpp to add support in the ruleset.
/**
* Creates a blank ruleset for a certain
* type of inventory section.
* @param id String defining the id.
* @param _resLevel int restriction level for item placement.
*/
RuleInventory::RuleInventory(const std::string &id): _id(id), _x(0), _y(0), _type(INV_SLOT), _resLevel(1), _listOrder(0), _hand(0)
void RuleInventory::load(const YAML::Node &node, int listOrder)
{
_resLevel = node["PlacementRestrictionLevel"].as<int>(_resLevel);
/**
* Gets the restriction level. 0 never restricted, 1 restricted for items with slot lists (default), 2 always restricted.
* @return restriction level.
*/
bool RuleInventory::getResLevel() const
{
return _resLevel;
}
With the property added we need to send the slots resLevel to the item along with the slots string ID when we check for compatibility in BattleScape/Inventory.cpp.
/**
* Picks up / drops an item.
* @param action Pointer to an action.
* @param state State that the action handlers belong to.
*/
void Inventory::mouseClick(Action *action, State *state)
{
// Check if this inventory section supports the item
if (!_selItem->getRules()->canBePlacedIntoInventorySection(slot->getId(), slot->getResLevel()))
And finally we need to catch the resLevel parameter and use it to determine item applicability in Mod/RuleItem.cpp.
/**
* Checks if the item can be placed into a given inventory section.
* @param inventorySection Name of the inventory section (RuleInventory->id).
* @param resLevel restriction level of the inventory section (RuleInventory->_resLevel).
* @return True if the item can be placed into a given inventory section.
*/
bool RuleItem::canBePlacedIntoInventorySection(const std::string &inventorySection, int &resLevel) const
{
// allow default items in unrestricted inventory sections.
if (resLevel == 1 && _supportedInventorySections.empty())
return true;
// always possible to put an item on the ground or in fully unrestricted slots
if (inventorySection == "STR_GROUND" or resLevel == 0)
return true;
// otherwise check allowed inventory sections
return std::find(_supportedInventorySections.begin(), _supportedInventorySections.end(), inventorySection) != _supportedInventorySections.end();
}
I submitted a pull request for the code as I wrote it to the Meridian branch for convenience. I triple checked it a few times and I don't think there's anything blatantly wrong in it, but IDC if you use my code or even do it the way I came up with. My approach was to do it without adding any new functions except a getter, and put it alongside your old code.
PS, huge thanks for all the work extending OXC! And thanks for reading all this too btw.