Talk:OnItemAdded - ObjectReference

From the CreationKit Wiki
Jump to navigation Jump to search


Script to Show Gift window and Track Items Given[edit source]

This is used for the Player to feed his animal companion. The FormList is created in the CK and includes all the food (Potion & Ingredient) items I want to consider food for the animal.

FormList Property FoodList Auto
Bool hasBeenFedToday = False

Function FeedCompanion()
	AddInventoryEventFilter(FoodList)
	ShowGiftMenu(True, FoodList, False, False)
	RemoveAllInventoryEventFilters()
EndFunction

Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
	If akSourceContainer == Game.GetPlayer()
		self.RemoveItem(akBaseItem,aiItemCount)
		If !hasBeenFedToday
			hasBeenFedToday=True
		EndIf
	EndIf
EndEvent

--Sollar 02:58, 28 June 2012 (EDT)




Script for Quest Stage Advancing Using OnContainerChanged[edit source]

Here is a sample script using an Event OnContainerChanged block instead of an Event OnItemAdded block:

; Quest stage advances when the player finds the quest item:
Scriptname AAFoundTheQuestItem extends ObjectReference  

Event OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer)
        if (akNewContainer == Game.GetPlayer())
                AAQuest.SetStage (15)
        endif
EndEvent

Quest Property AAQuest  Auto

--David Brasher 19:24, 27 April 2012 (EDT)


Script for Quest Stage Advancing Using OnActivate[edit source]

Here is a script that can use an Event OnActivate block instead of an Event OnItemAdded block:

; Quest stage advances when the player finds the quest item:
Scriptname AAFoundTheObject extends ObjectReference  

Event OnActivate (ObjectReference akActionRef)
        AAQuest.SetStage (15) 
EndEvent  

Quest Property AAQuest  Auto

Note that the quest stage advances when the player activates the item, not when the player takes it and adds it to inventory. The player could forget to take an item like a book and could leave it in the dungeon. Then the player would walk all the way back to the quest-giver and realize that he or she didn't have the item and needed to go back to the dungeon and get it.

--David Brasher 18:40, 27 April 2012 (EDT)

Facts about OnItemAdded[edit source]

The following are true to the best of my knowledge.

  • OnItemAdded and OnItemRemoved cannot run concurrently with themselves.
    • If the player adds X items in rapid succession, then X calls to OnItemAdded will be queued. These calls will exist as suspended stacks in the Papyrus engine, and they will be executed in order, one by one.
  • OnItemAdded and OnItemRemoved can run concurrently with each other.
    • If you call RemoveItem from inside of an OnItemAdded call, then OnItemRemoved will begin executing immediately -- and concurrently with the OnItemAdded call that caused it.
      • Actually, the OnItemRemoved call will be queued immediately. If another OnItemRemoved call is running, the newly-queued call won't run immediately.
  • If the Form uses an inventory event filter, and the player picks up an item that doesn't match the filter, then an OnItemAdded call will not be queued. A new script stack will not be created in the Papyrus engine.
  • Inventory events are generated per item-stack transferred, not per individual item. If a player takes 50 Nirnroot from a container as a single operation, one OnItemAdded event will be fired. If the player takes each of those Nirnroot one-by-one, however, then fifty OnItemAdded events will fire.

Examples of mass item operations:

  • A player who stores alchemy ingredients in a container at their home. A player could store thirty different kinds of ingredients at a time; or, if they wish to start brewing potions, they could Take All of the container's contents. There are roughly ninety ingredients in the base game, so that's upwards of ninety OnItemAdded events that could be generated.
  • Using Take All on weapon or armor containers in QASmoke.

Mistakes to avoid:

  • Reacting to the addition of a specific type of item
    • DON'T just compare akBaseItem to a known Form. If you don't use inventory event filters, then your OnItemAdded event will fire for completely irrelevant item additions, creating unnecessary script stacks. Mass item operations could result in too many such stacks, leading to stack dumping.
    • DO use inventory event filters. These are handled within the game engine, and will prevent your script from creating useless script stacks.
  • Reacting to an item being added, but only after the player leaves the inventory menu
    • DON'T use Utility.Wait(a) inside of OnItemAdded. If the player adds b items, the first call will run immediately after the inventory menu is closed. The other (b - 1) calls will each wait for a seconds; it will take at least a * (b - 1) seconds for them to complete. During that time, the player can add more items to their inventory, queuing additional OnItemAdded calls and further stretching the time it takes for all queued calls to finish running. If too many calls end up queued, Skyrim will dump stacks.
    • DO use RegisterForSingleUpdate(a), and do your actual processing in an OnUpdate event. If the player adds b items, the first call will register a single update event; the additional calls will simply re-register that same event, harmlessly. This won't fully protect you from stack dumping, but it will reduce the time it takes for all OnItemAdded stacks to finish executing; it will take larger item operations to cause stack dumping.
  • Reacting to items being added, but only after the player leaves the inventory menu (SKSE)
    • DON'T rely solely on RegisterForSingleUpdate. It will help, but it's not bulletproof.
    • DO disable your inventory events entirely when the player opens the inventory menu, by applying an inventory event filter that uses an empty form list. Re-enable your inventory events by removing that filter when the player closes the inventory menu.
    • DO keep in mind that another mod's imperfect OnItemAdded handling may, in the most extreme of extreme cases, cause your OnMenuClose stack to get dumped. If this happens, your mod won't pay attention to further item additions or removals until the next time the player closes the inventory menu.
    • DO keep in mind that this method survived a stress test in which I COC'd to QASmoke and emptied out all of the Dragonborn containers. So, you know, there's that.

DavidJCobb (talk) 2015-02-28T05:05:30 (EST)

My experience with both of the events aren't very good to say the least. A lot of that you stated, I've made the mistake of doing, and probably many others have too.--Terra Nova2 (talk) 2015-03-03T09:11:39 (EST)
Perhaps it might be a good idea to create a section in the main article for this? I also have information on safely processing masses of OnHit events (in the "stack dumping" subpage of my userpage), which could probably go in that article. DavidJCobb (talk) 2015-03-04T04:06:40 (EST)
It's you call. --Terra Nova2 (talk) 2015-03-04T07:51:20 (EST)
I might want to add to the discussion. I'm currently trying DavidJCobb's input on a function that will show follower inventory/carry weight in the trade menu. Bascially what OnItemAdded/Removed does, is updating the float/integer on my widget, for correct display of numbers in the trade menu. I had a lot of problems when "spaming" the mouse button for rapid succession of adding/removing items, completely messing up the displayed numbers, because of the queued stacks, and thus producing an enormous amount of error log none stacks. Using an empty formlist entirely removed the problems, though now the numbers are responding a bit slower. But if this helps to neglect error logs and messed up numbers, I'm all good with it. --Mofakin (talk) 2015-16-10T09:29:20 (EST)