Limited Bag with the Universal Inventory

Hi guys,

Last version of twine/sugarcube

I have a question about HiEv’s UInv module. Is it possible to create bags that only accept certain types of objects (for example, a bag that only accepts the gold coin item or only items with the type “money”).

I use the drag and drop system, so I also need to be able to avoid moving an object into the wrong bag. Thanks!

1 Like

The answer to that is yes, it can do that. Currently the method is a bit more crude than I’d like, but “blacklists” and “whitelists” for item types in bags is probably going to be a post-v1.0 feature.

I tried to do it myself and ran into a few bugs with the event handler system, so I’ve released UInv v0.9.7.1 as a bugfix release so this will work properly.

Once you’ve updated to UInv v0.9.7.1, what you’ll need to do is set up an event handler for “table”/“Accept” events using the AddEventHandler() function.

To do that, you’ll need to create a “table”/“Accept” event handler in your code like this:

<<run UInv.AddEventHandler("table", "Accept", "acceptTest")>>

That sets up a SugarCube widget or macro, or a JavaScript function, to handle accepting/rejecting items on “table”/“Accept” events.

In this case, the above code will tell UInv to call the <<acceptTest>> widget whenever an “Accept” event is triggered on a table.

Next, you need to create a widget in a non-special non-story passage with a “widget” tag. The code you put there will be something like this:

<<widget "acceptTest">>
	<<set _e = $args[0]>>
	<<if _e.destBag == "CoinPouch">>
		<<set _UInvReturn = {
			acceptVal: !!UInv.ItemHasTag(_e.srcBag, _e.draggedItem, "type", "money") 
		}>>
	<</if>>
<</widget>>

That widget checks to see if the item is being dropped on a bag named “CoinPouch”. If it is, it then checks to see if the item has a “money” tag included within its “type” property. If it doesn’t, then it won’t let that item drop into the “CoinPouch” bag. (See the AddEventHandler() function for details.)

I’ve added another passage to the sample code included with UInv to demonstrate how this works as well.

Please let me know if you have any questions or problems with that. :slightly_smiling_face:

1 Like

It’s working perfectly! I had missed in the documentation the options to put in the return values…

I put here my complete solution using javascript. It also handles the exchange between two items.

  1. Add to your bags the array property acceptedType defining all accepted items type
  2. Add the following javascript code

setup.eventCheckItemType = function (event) {
let ret = {
acceptVal: false
};

let srcItemToDestBag = false;
let destItemToSrcBag = false;
let bagSrcAcceptedTypeArray = UInv.GetBagPropertyValue(event.srcBag, “acceptedType”);
let bagDestAcceptedTypeArray = UInv.GetBagPropertyValue(event.destBag, “acceptedType”);
let itemSrcTypeArray = ,
itemDestTypeArray = ;

if (UInv.BagHasItem(event.srcBag, event.draggedItem)) {
itemSrcTypeArray = UInv.GetItemPropertyValue(event.srcBag, event.draggedItem, “type”);

  for (let itemSrcType of itemSrcTypeArray) {
  	if (bagDestAcceptedTypeArray.includes(itemSrcType)) {
  		srcItemToDestBag = true;
  		break;
  	}
  }

} else {
return ret;
}

if (event.droppedOnItem == “”) {
destItemToSrcBag = true;
} else if (UInv.BagHasItem(event.destBag, event.droppedOnItem)) {
itemDestTypeArray = UInv.GetItemPropertyValue(event.destBag, event.droppedOnItem, “type”);

  for (let itemDestType of itemDestTypeArray) {
  	if (bagSrcAcceptedTypeArray.includes(itemDestType)) {
  		destItemToSrcBag = true;
  		break;
  	}
  }

} else {
return ret;
}

if (srcItemToDestBag && destItemToSrcBag) {
ret.acceptVal = true;
}

return ret
}

UInv.AddEventHandler(“table”, “Accept”, “eventCheckItemType”, );

HiEv, thank you for your response, and thank you for your work, this inventory system is impressive!

If you’re doing what I think you’re trying to do, here’s a more efficient way of writing that:

setup.eventCheckItemType = function (event) {
	let bagDestAcceptedTypeArray = UInv.GetBagPropertyValue(event.destBag, "acceptedType");
	let srcItemToDestBag = UInv.ItemHasAnyTag(event.srcBag, event.draggedItem, "type", bagDestAcceptedTypeArray);
	let destItemToSrcBag = true;
	if (event.droppedOnItem != "") {
		let bagSrcAcceptedTypeArray = UInv.GetBagPropertyValue(event.srcBag, "acceptedType");
		destItemToSrcBag = UInv.ItemHasAnyTag(event.destBag, event.droppedOnItem, "type", bagSrcAcceptedTypeArray);
	}
	let ret = { acceptVal: srcItemToDestBag && destItemToSrcBag };
	return ret
}

UInv.AddEventHandler("table", "Accept", "eventCheckItemType");

That should make sure that at least one of the tags in the destination bag’s “acceptedType” property’s array matches at least one of the tags in the dragged item’s “type” property’s array. Similarly, if an item was dropped onto, it checks to make sure that that item can be transferred to the source bag.

Anyways, glad you like UInv. Life’s been getting in the way of working on it more, but I’ve been trying to get back to it recently. Part of the event handler fixes you need had been done around a week ago when I was adding the “cacheImages”/“Idle” event.

I have some other stuff I’ve been working on for UInv, but none of it’s ready to be released yet. Hopefully, if things go well, I’ll be able to release some of it within a few months.

Also, not sure if you’ve seen this, but I also have a bunch of other random Twine/SugarCube sample code snippets I update periodically. Feel free to use any of that code as well.

Enjoy! :slight_smile:

1 Like

Hehe, you’ve thought about a lot of function, it’s going to take time to master the module! Your code is raising the bug ‘ItemHasAnyTag cannot find item “itemname”’

The bug appears just after the drop and only when I switch from a bag to another one. I didn’t check precisely, but I feel like just after the drop, the inv system considers that the item is on the new bag, but the event data received by the accept event function are not yet upated (item is still on the old bag).

If we add the test to check that the src item is in the src bag (same for dest), it’s working. This code using the ItemHasAnyTag function is working well:

setup.eventCheckItemType = function (event) {
	let bagDestAcceptedTypeArray = UInv.GetBagPropertyValue(event.destBag, "acceptedType");
	let srcItemToDestBag = true,
		destItemToSrcBag = true;

	if (UInv.BagHasItem(event.srcBag, event.draggedItem)) {
		let srcItemToDestBag = UInv.ItemHasAnyTag(event.srcBag, event.draggedItem, "type", bagDestAcceptedTypeArray);
	}
	
	if (event.droppedOnItem != "" && UInv.BagHasItem(event.destBag, event.droppedOnItem)) {
		let bagSrcAcceptedTypeArray = UInv.GetBagPropertyValue(event.srcBag, "acceptedType");
		destItemToSrcBag = UInv.ItemHasAnyTag(event.destBag, event.droppedOnItem, "type", bagSrcAcceptedTypeArray);
	}

	let ret = {
		acceptVal: srcItemToDestBag && destItemToSrcBag
	};

	return ret
}

Anyway, I’m looking forward to seeing the new features you’re cooking up for us!

I think the problem might actually be that I assumed that “acceptedType” property would be an array value on all of your bags. If it’s not, then this should work:

setup.eventCheckItemType = function (event) {
	let srcItemToDestBag = true;
	let destItemToSrcBag = true;
	let bagDestAcceptedTypeArray = UInv.GetBagPropertyValue(event.destBag, "acceptedType");
	if (UInv.isArray(bagDestAcceptedTypeArray)) {
		srcItemToDestBag = UInv.ItemHasAnyTag(event.srcBag, event.draggedItem, "type", bagDestAcceptedTypeArray);
	}
	if (event.droppedOnItem != "") {
		let bagSrcAcceptedTypeArray = UInv.GetBagPropertyValue(event.srcBag, "acceptedType");
		if (UInv.isArray(bagSrcAcceptedTypeArray)) {
			destItemToSrcBag = UInv.ItemHasAnyTag(event.destBag, event.droppedOnItem, "type", bagSrcAcceptedTypeArray);
		}
	}
	let ret = { acceptVal: srcItemToDestBag && destItemToSrcBag };
	return ret
}

That will allow all drops on a bag if the “acceptedType” property isn’t there or isn’t an array on that bag.

If you still have problems, let me know, because the dropped item shouldn’t be in the destination bag until after this event handler triggers (assuming that the return value doesn’t include { acceptVal: false }, in which case the dropped item will stay where it was).