OpenXcom Forum

Modding => OpenXcom Extended => Topic started by: darkestaxe on August 25, 2018, 11:25:34 pm

Title: [Suggestion] Gear slot restriction levels (w/ code)
Post by: darkestaxe on August 25, 2018, 11:25:34 pm
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.
Code: [Select]
 * 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.
Code: [Select]
 * 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.
Code: [Select]
 * 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.
Title: Re: [Suggestion] Gear slot restriction levels (w/ code)
Post by: Meridian on September 30, 2018, 10:12:16 am

Did you try to compile your code?
For me it doesn't work...

1/ canBePlacedIntoInventorySection(...) takes a new parameter, but it's not defined in the header, or even in the body
2/ member variable _resLevel not defined in the header
3/ "if (inventorySection == "STR_GROUND" or resLevel == 0)" ... doesn't compile in VS with default settings, use || instead of or
4/ resLevel is an undefined variable or parameter

a/ PlacementRestrictionLevel should begin with a lower case letter
b/ one commit instead of 3 pls