Jump to content

OnItemAdded - Problem with potions


Ghaunadaur

Recommended Posts

Ok, I'm fiddling around with a slightly modified version of the PlayerBookShelfContainerScript. It's for potions. The problem is, when I add some potions of the same type, it seems the game will not always treat them as such. For example: I add 25 potions of the same type (maximum is 12) and the OnItemAdded event gets called 2 times. First time it tells me 20 potions were added, second time the messagebox tells me 5 potions added. The 20 potions are returned to the players inventory, the other 5 get placed on the rack. Is there any way to work around this problem, so the script treats all 25 potions as the same type?

 

 

This is the relevant code:

Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
;Trace("POTIONCASE - Adding " + akBaseItem + " to the Potion Container")

debug.messagebox(aiItemCount + " items added.")
if (akBaseItem.HasKeyword(VendorItemPotion)) ||  (akBaseItem.HasKeyword(VendorItemPoison)) || (PotionRackClutterList.HasForm(akBaseItem))
; If the item being added is a potion then check to see if there is room in on the rack.
	;Trace("POTIONCASE - Form being Added " + akBaseItem + " is a Potion!")
	if ((aiItemCount + CurrentPotionAmount) <= MaxPotionsAllowed)
		; There's room on teh rack, manage the potion placement
		;Trace("POTIONCASE - " + CurrentPotionAmount + "/" + MaxPotionsAllowed + " There is room for another potion, lets place it on the rack.")
		AddPotions(akBaseItem, aiItemCount)
		debug.messagebox(aiItemCount + " potions added.")
		CurrentPotionAmount = CurrentPotionAmount + aiItemCount
	else
		; There is no room on the rack.  Tell the player this and give him his potion back.
		;Trace("POTIONCASE - " + CurrentPotionAmount + "/" + MaxPotionsAllowed + " There's no more room for potions on this rack.")
		utility.waitMenuMode(0)
		;MessageBox("You can't place that many potions on this rack")
		PotionRackNoMoreRoomMESSAGE.Show()
		;Trace("POTIONCASE - Remove it from this container...")
		BlockPotions = TRUE
		self.RemoveItem(akBaseItem, aiItemCount, true, Game.GetPlayer())
		debug.messagebox(aiItemCount + " potions removed.")
		;Trace("POTIONCASE - ...and give it back to the player")
	endif
else
	; The item placed in the container isn't a potion, so give the player back and tell him only potions are allowed.
	;Trace("POTIONCASE - Form " + akBaseItem + " is NOT a Potion!")
	;Trace("POTIONCASE - Since the placed item wasn't a potion remove it from the container...")

	self.RemoveItem(akBaseItem, aiItemCount, true, Game.GetPlayer())
	;Trace("POTIONCASE - ...and give it back to the player")

	;(Game.GetPlayer()).AddItem(akBaseItem, aiItemCount, True)
	utility.WaitMenuMode(0)
	;MessageBox("You can only place potions on this rack")
	PotionRackNotAPotionMESSAGE.Show()
	debug.messagebox(aiItemCount + " items removed.")
endif

endEvent

Link to comment
Share on other sites

  • 2 months later...

Sounds like a problem with AddItem rather than OnItemAdded.

Are you absolutely positively sure that the potions all use the same base form?

 

Whiule I cannot speak for the OP, in my case its simply OnItemAdded applied to a chest. If the player tries to add potions or ingredients it splits the add into multiple calls, even if they stored all the items in the stack at the same time.

 

Curiously it always uses the same combination, too... eg adding a stack of 60 butterfly wings always results in 4 calls - 54 items, then 4 items, then 1 and 1. Always.

 

I've also heard the bug happens with large numbers of vanilla silver swords... JUST silver swords, mind you. Whats odd is that it sems to only happen with specific Forms. I have other ingredients that seem to add properly as one big drop. Cant figure out WHY mind you...

 

I'm trying to work on a more reliable method to use as a fix, basically by making an array out of a formlist.

Link to comment
Share on other sites

  • 3 weeks later...

MYSTERY SOLVED:

 

It has to do with stacks of items the player found in containers versus items found in the world. "Real World" items have an ObjectRef in addition to a Form. Items which have only ever been in containers lack an ObjectRef.

 

OnItemAdded expects an ObjectRef, or null. So lets say you have 50 arrows... 20 of them you bought, 20 you found in a chest, and ten you plucked out of corpses. The chest/vendor ones have never seen the light of day and lack ObjectRefs. The plucked ones were in the real world, and have ObjectRefs.

 

From what I can tell, if you dump them in a Chest, OnItemAdded would be called at least 10 times, maybe more. Once for each arrow that still has an Object Ref, because OnItemAdded requires it, which may or may not include X number of non-Ref'ed Form-only arrows.

 

It looks like the Form-only arrows somehow get grouped along with those that have object refs... no clue here as to what the logic is here, but my guess would be semi-chronologically... you find an arrow, buy 8 more, find another arrow, buy 11 more, it comes across as a group of 9 (first Ref, and 8 friends) and a group of 12 (second Ref and remainder). I think its still more complicated than this because I'm not factoring in garbage collection (Objetc Refs sometimes goes away when the object is put in a container, and sometimes they dont), but after working on my Container Spell Scripts for 2 weeks now I'm fairly positive it works something along these lines.

 

I know for a fact that when I added a stack of 1000 spriggan saps via console commands, all 1000 went enmasse into a single OnItemAdded. But the 1005 Saltpiles, 5 of which were collected (stolen) from an alchemists shelf at various times, went into the eventhandler in 5 calls, supporting my theory.

 

It's an interesting peek into how Skyrim works under the hood. It's likely also a reason for Save Bloat because it means those 1005 Saltpiles are being stored in 5 lists rather than one.

 

IT would be an interesting exercise to make a utility chest that the user can dump all his items into, and have it strip out the ObjectRefs, then return the items to the player. My guess is that the resulting savefile would be smaller, particularly for packrat players such as myself who never vendor / trash anything.

Edited by Arodicus
Link to comment
Share on other sites

That sounds about right. If an item is not persistent, it gets destroyed when placed in a container, then re-created as an object reference from its base form when dropped into a worldspace. At least, that's how I understand it.
Link to comment
Share on other sites

  • 2 weeks later...

I starting to think this is also the root cause of several bugs involving formlists, for example the remove() script which only works intermittently, and various CTDs when using Add.... I never seem to have problems when using items I've added via script, only when "real world" items come into play do the bugs start to appear.

 

It's starting to look as if a Form passed in with an ObjectRef is actually slightly different than an identical Form that doesnt have such an association, and I'm guessing the internal binary code notices this difference and chokes if there's a discrepency.

 

Case in point, if I add the onitemadded akBaseItem of several different objects added via addItem() into a Formlist, I appear to have no problems removing them, in any order - the wiki says its bugged and thus I should only be able to remove one. However if I add the akBaseItem from any object that I pick up in the world, I cannot remove any more items from the list. I haven't verified this, but after dealing with my container spells now for several weeks, this "feels" like the real problem. I'm guessing that the Form might actually contain a secret reference it its own Object Ref child (an OOP no-no) , and that this is the cause of many of the weird bugs we get as modders.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...