Jump to content

How to use GetInveRefsForItem


Recommended Posts

Supposedly this command will give you an array of stacks of an item in a container. I want to count the empty soulgems in the player's inventory for soulgems that match the target's soul size.

 

My Challenge: To display the number of empty soul gems that match the target's soul size every time I cast a soul trap spell on an Actor.

 

Here is what I have:

if rTarget.IsCreature == 0
   set iSoulSize to 6
   let arrSoulGems := PlayerRef.GetInvRefsForItem BlackSoulGem
  elseif rTarget.GetLevel >= 18
   set iSoulSize to 5
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty5Grand
  elseif rTarget.GetLevel >= 13
   set iSoulSize to 4
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty4Greater
  elseif rTarget.GetLevel >= 7
   set iSoulSize to 3
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty3Common
  elseif rTarget.GetLevel >= 2
   set iSoulSize to 2
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty2Lesser
  else
   set iSoulSize to 1
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty1Petty
  endif
  set iPetty to 0
  set iLesser to 0
  set iCommon to 0
  set iGreater to 0
  set iGrand to 0
  set iBlack to 0
  set bAzuraStar to 0
  if arrSoulGems
   let iArrSize := ar_Size arrSoulGems
   set iArrSize to iArrSize - 1
   PrintC "Array size is %g" iArrSize
   while iArrSize >= 0
    let rItem := arrSoulGems[iArrSize]   ;; FIXED!!! <<============  I DON'T THINK THIS WORKS. 
    let rItemBase := rItem.GetBaseObject
    let iCurrSoulLevel := rItem.GetCurrentSoulLevel   
    let iGemCount := rItem.GetRefCount
    PrintC "RFFnOnSoulTrap ------ Stack Count %g for %n is %g, Current Soul Level = %g", iArrSize, rItemBase, iGemCount, iCurrSoulLevel
    if iCurrSoulLevel == 0 && iGemCount > 0  ; Soulgem & empty
     if iSoulSize == 1
      if rItemBase == SoulGemEmpty1Petty 
       ;PrintC "RFFnOnSoulTrap ------ Stack Count for %n is %g, Current Soul Level = %g", rItemBase, iGemCount, iCurrSoulLevel
       set iPetty to iPetty + iGemCount
      endif
     elseif iSoulSize == 2
      if rItemBase == SoulGemEmpty2Lesser  ;rItem.GetSoulGemCapacity == 2
       ;PrintC "RFFnOnSoulTrap ------ Stack Count for %n is %g, Current Soul Level = %g", rItemBase, iGemCount, iCurrSoulLevel
       set iLesser to iLesser + iGemCount
      endif
     elseif iSoulSize == 3
      if rItemBase == SoulGemEmpty3Common  ;rItem.GetSoulGemCapacity == 3
       ;PrintC "RFFnOnSoulTrap ------ Stack Count for %n is %g, Current Soul Level = %g", rItemBase, iGemCount, iCurrSoulLevel
       set iCommon to iCommon + iGemCount
      endif
     elseif iSoulSize == 4
      if rItemBase == SoulGemEmpty4Greater  ;rItem.GetSoulGemCapacity == 4
       ;PrintC "RFFnOnSoulTrap ------ Stack Count for %n is %g, Current Soul Level = %g", rItemBase, iGemCount, iCurrSoulLevel
       set iGreater to iGreater + iGemCount
      endif
     elseif iSoulSize == 5
      if rItemBase == AzurasStar
       set bAzuraStar to 1    
      elseif rItemBase == SoulGemEmpty5Grand
       ;PrintC "RFFnOnSoulTrap ------ Stack Count for %n is %g, Current Soul Level = %g", rItemBase, iGemCount, iCurrSoulLevel
       set iGrand to iGrand + iGemCount
      endif
     elseif iSoulSize == 6
      if rItemBase == BlackSoulGem
       ;PrintC "RFFnOnSoulTrap ------ Stack Count for %n is %g, Current Soul Level = %g", rItemBase, iGemCount, iCurrSoulLevel
       set iBlack to iBlack + iGemCount
      endif
     endif
    endif
    set iArrSize to iArrSize - 1
   loop ;
  endif

If I dump that array I get, I see the inventory refs it gives stacks of that soulgem, but I my code to process that array does not work.

 

Thanks!

 

OOPS. I have a typo in the array index variable.

 

Now that I fixed that I am seeing the same problem I have trying to loop through the player with the foreach command. The soulgem stacks I am getting are not what is in my inventory.

 

I just tested it with 18 empty Common soulgems in my inventory. When cast on a Fire Atronauch (a Common soul), my code reports there are 33 empty Commons. In the console I print each item from the array on a single. There is an item in the stack that has a count of 33 and a current soul size of 0 (empty).

 

I cannot get the number of gems that the code finds to match what is in my inventory.

Edited by GamerRick
Link to comment
Share on other sites

I don't how Oblivion handles soul gems when used, so I would make some notices and questions too:

 

1. Maybe it's only a formating of your script, but I feel that is something amiss with iSoulSize selection. Personaly I would do it like this:

;just for sure init of iSoulSize and cleaning a field
set iSoulSize to 0
let iArrSize := ar_Size arrSoulGems
if iArrSize > 0
   ar_Resize arrSoulGems 0
endif
;selecting soul level and filling a field
if rTarget.IsCreature == 0 ;no creature?
   set iSoulSize to 6
   let arrSoulGems := PlayerRef.GetInvRefsForItem BlackSoulGem
else ;checking creature level
  if rTarget.GetLevel >= 18
   set iSoulSize to 5
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty5Grand
  elseif rTarget.GetLevel >= 13
   set iSoulSize to 4
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty4Greater
  elseif rTarget.GetLevel >= 7
   set iSoulSize to 3
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty3Common
  elseif rTarget.GetLevel >= 2
   set iSoulSize to 2
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty2Lesser
  else
   set iSoulSize to 1
   let arrSoulGems := PlayerRef.GetInvRefsForItem SoulGemEmpty1Petty
  endif
endif

2. That condition "if arrSoulGems" - can it be used like this? I would remove it and make a condition:

...
let iArrSize := ar_Size arrSoulGems ;checking size after using OBSE function
PrintC "Array size is %g" iArrSize
if iSoulSize != 0 && iArrSize > 0 ;both variable and field are filled
   set iArrSize to iArrSize - 1
   ... 

3. So when you used a filled gem it will become one with "SoulGemEmpty..." as base object?

Edited by RomanR
Link to comment
Share on other sites

The "if arrSoulGems" is just making sure it actually is referencing something, since I don't know what the OBSE function will return if there are no soulgems of that type in my inventory. It either returns null or it returns an empty array. This way, I cover my ass either way.

 

The soultrap spell works by finding an empty soulgem in your inventory and then doing a SetCurrentSoulLevel on it. So the item remains the same base object (like SoulGemEmpty3Common) but is now different from the other ones by info saved in that instance of the object.

 

The only way to get an inventory ref on an object in your inventory (or any container for that matter) is by using a foreach loop or using the GetInveRefsForItem. For the latter I should have one array item that is a stack of the soulgems that are still empty. I am getting something else. The numbers are way off.

 

I have been plugging away with this for over a week now. I am out of ideas and things to try. For now, I want to figure out how to wirte debug to a file using pluggy. The only mod I have that uses it successfully is RefScope. Wish me luck.... :ermm:

Edited by GamerRick
Link to comment
Share on other sites

For me I experienced the second case - if I define a field and leave it empty, the calling functon which returns a field will not change it in case of empty results. So afterwards I update the size variable and if field is empty (size 0), I can be sure that function returned nothing.

 

As it seems that your script you showed is a part of whole I'm assuming that before using GetInvRefsForItem the field must be empty, so the cleanup before this function or aftewards after processing is needed. Documentation of OBSE is in my opinion unclear what happens to a field when the script ends, so I'm always using ar_Resize command to zero and destroying a field using ar_Null at end of my scripts, constructing it again on start.

 

Poking at OBSE docs I see that GetCurrentSoulLevel function is used on actor, not a Soul Gem. For gem I see GetSoulLevel - "returns the soul level currently in the soul gem".

Link to comment
Share on other sites

Scrap that part beginning "Poking at OBSE docs..." part. After I made testing function for it it seems that docs part is somewhat wrong. I managed to use GetCurrentSoulLevel on a field filled by soul gems and it's really returning their current soul level. But problem arised - I can't manage GetCurrentSoulLevel or GetSoulLevel to make it work on actors, be it reference or base object. They always return zero.

 

Oh well, at least I can present my test function for you to play with. It has two inputs - base object of soul gem and its soul level. After calling it return a count of matching soul gems of requested soul level.

 

 

scn RomRFnMatchGems

ref gem ;input soul gem as base object!!!
ref gem2
int size 
int index
int count2 ;output count of matched gems
int count
int s_level ;input soul level
int g_level
array_var soulGems

begin function {gem, s_level}
	set count2 to 0
	let size := ar_Size soulGems
	if size == -1
		let soulGems := ar_Construct array
	endif
	let size := ar_Size soulGems
	if gem != 0 && size == 0 ;gem reference is valid and field is defined
		if s_level >= -1 && s_level < 6 ; soul level is within range -1 = all levels, 0 - 5 from petty to grand
			let soulGems := player.GetInvRefsForItem gem
			let size := ar_Size soulGems
			if size > 0
				set index to 0
				set count to 0
				while index < size
					let gem2 := soulGems[index]
					let g_level := gem2.GetCurrentSoulLevel
					if s_level == -1
						let count := gem2.GetRefCount
						;print "All match mode:"
						;print $gem2+" count: "+$count+" level: "+$g_level
					else
						if g_level == s_level
							let count := gem2.GetRefCount
							;print $gem2+" count: "+$count+" level: "+$g_level
						else
							set count to 0
						endif
					endif
					set count2 to count2 + count
					set index to index + 1
				loop
			endif
		endif
	endif
	;cleanup
	let size := ar_Size soulGems
	if size > 0
		ar_Resize soulGems 0
	endif
	let soulGems := ar_Null
	SetFunctionValue count2
end

 

 

Link to comment
Share on other sites

Yea I know, that is why I do the level check on creatures to get their soul level. Because NOTHING else I tried works on creatures that are not a hard coded level but a PC level offset instead.

Same with the various Get commands that return a soul level. The GetSoulLevel takes a BaseID, not a reference. Though you could be right about the GetCurrentSoulLevel being made for actors. It seems to work for the soulgem inventory refs I have to identify the ones I filled already.

And yes, I do have a command to get rid of the array below that (to enable the garbage collector to take it): let arrSoulGems := ar_null

 

dfd

Edited by GamerRick
Link to comment
Share on other sites

Well, if all formal needs were met, I'm at my wits end too. If you're in mood you can try my fuction to compare the result of yours and mine, but as I can't see some obvious error in your script, I don't know what to suggest else.

Link to comment
Share on other sites

Thanks for trying. Your code is doing exactly the same thing mine is as far as looping through the array you get from the GetInvRefsForItem.

 

Did you test it to see if it works?? If you do the ar_dump command on the array, what do you see in the console?

 

If I have 8 empty common soulgems on me (8 SoulGemEmpty3Common that are empty and none that have a soul in them), I expect to see ONE stack in the array where the RefCount is 8 and the current soul level is 0. I get an array of 10+ items. Most have a refcount of -1. Then I see one stack with 16 empty soulgems. Other times I may see one stack with 1 and another with 15. The results I have been getting aren't totally repeatable. In fact it works fine with Grand and Black soulgems. Why not the others then?

 

So it seems to be the GetRefCount instruction that is failing here.

 

I have seen other weird things with the stacks I get from the foreach command. If there is nothing wrong with the script, and you don't see the weirdness I am seeing, it's possible my game is corrupted or something is broken with OBSE. I already asked the OBSE person about this, but (as you probably already know) they won't even consider that there's something wrong with their code unless I can prove it beyond any doubt. So, I am trying to get to the bottom of this.

 

So, what I really need here is for someone else to try this out and see if it works for them or not.

 

One wild guess I have now is that the latest xOBSE and/or some plugin (DLL file) I installed is not compatible with Win 7. But I reverted to OBSE 21 and started from an old save to test this, but I get the same wrong results.

 

Thanks.

Edited by GamerRick
Link to comment
Share on other sites

Yes, I tested it. I took to my inventory one black soul gem (empty), 5 empty grand souls gems and 4 grand soul gems filled with grand soul.

I went to some cave and began testing my function with simple work flow - casting my test spell before combat and after a creature died, capturing its soul to one of empty grand soul gems. A function had a print commands uncomented and for test used -1 as soul level parameter to show all grand gems regardless os soul level filled. The printouts didn't showed any oddities, so I posted my function here.

 

Test touch spell was used with this script:

 

 

scn RomRSoulGemMatchSpellScript

ref actor
ref a_base
ref gem
short init
int index
int size
int a_soul
int g_soul
int g_count
int count
array_var soulGems

begin ScriptEffectStart

	set actor to GetSelf
	if actor != 0
		print "Target hit"
		if actor.IsActor != 0 ;&& actor.GetDead == 0
			if actor.GetIsCreature != 0
				let a_base := actor.GetBaseObject
				let a_soul := actor.GetCurrentSoulLevel
				if a_soul == 0
					set a_soul to 1
				endif
			else
				set a_soul to 6 ;actor is a human
			endif
		endif
	endif

	print $actor+"'s soul level is: "+$a_soul
	if a_soul > 0
		if a_soul == 6
			set gem to BlackSoulGem
			set g_soul to -1
			let count := Call RomRFnMatchGems gem g_soul
			set gem to BlackSoulGemGrand
			let count := Call RomRFnMatchGems gem g_soul
		else
			set g_count to 0
			set g_soul to -1
			set gem to SoulGemEmpty5Grand
			let count := Call RomRFnMatchGems gem g_soul	
			set g_count to g_count + count
			set gem to SoulGem5Grand5GrandSoul
			let count := Call RomRFnMatchGems gem g_soul
			set g_count to g_count + count
			set gem to SoulGem5Grand4GreaterSoul
			let count := Call RomRFnMatchGems gem g_soul
			set g_count to g_count + count
			set gem to SoulGem5Grand3CommonSoul
			let count := Call RomRFnMatchGems gem g_soul
			set g_count to g_count + count
			set gem to SoulGem5Grand2LesserSoul
			let count := Call RomRFnMatchGems gem g_soul
			set g_count to g_count + count
			set gem to SoulGem5Grand1PettySoul
			let count := Call RomRFnMatchGems gem g_soul
			set g_count to g_count + count
			print "This part found "+$g_count+" matching gems"
		endif
	endif


end

 

 

 

It's a very quick work, due to not working GetCurrentSoulLevel the soul level of creature reported will be always 1 and creature part check only grand soul gems now.

 

Edit: Oh sorry, I missed part in your post saying about testing grand and black soul gems. But as I inserted ar_Dump command in my function and testing calls to it using petty and lesser soul gems (I "borrowed" some from a local Mage Guild), comparing results printed by function and ar_Dump command didn't show anything unusual again (certainly not negative stack values). So at least on my computer these two functions behave normal (GetRefCount and GetInvRefsForItem).

Edited by RomanR
Link to comment
Share on other sites

OK, as further testing of my function doesn't reveal any problem, I made enchanced version of my script test spell which calls this function. I made also success on finding right OBSE function to use: it's "GetCreatureSoulLevel" or "GetActorSoulLevel". But for creatures with PCLevelOffset you still need a check based on their level, as both functions report what is edited in actor's edit window only. Outputs are to console only and script doesn't report Azura's Star.

 

Here it is:

 

 

scn RomRSoulGemMatchSpellScript

ref actor
ref gem
short init
int index
int size
int a_soul
int a_soul2
int g_soul
int g_count
int count
short match
short higher
string_var str_soul

begin ScriptEffectStart
	set actor to GetSelf
	if actor != 0
		print "Target hit"
		if actor.IsActor != 0 ;&& actor.GetDead == 0
			if actor.GetIsCreature != 0
				; level check is based on a chart from UESP website
				set a_soul2 to actor.GetLevel 
				print $actor+" is at level "+$a_soul2+"."
				if a_soul2 == 1 
					set a_soul to 1 ;petty
				elseif a_soul2 > 1 && a_soul2 < 7 
					set a_soul to 2 ;lesser
				elseif a_soul2 >= 7 && a_soul2 < 13
					set a_soul to 3 ;common
				elseif a_soul2 >= 13 && a_soul2 < 18
					set a_soul to 4 ;greater
				elseif a_soul2 >= 18
					set a_soul to 5 ;grand
				endif
				let a_soul2 := actor.GetCreatureSoulLevel
				; if these two checks doesn't match
				if a_soul != a_soul2 
					print "Soul checks for this creature doesn't match!"
					print "From level check: "+$a_soul+" OBSE function: "+$a_soul2
					if actor.IsPCLevelOffset
						print "Creature has level offset - selected soul level from level check."
					else ;OBSE function seems reporting static level creatures right
						set a_soul to a_soul2
						print "Creature has static level - selected soul level from OBSE function."
					endif
				endif 
			else
				set a_soul to 6 ;actor is a human
			endif
		endif
	endif

	if a_soul > 0
		print $actor+"'s soul level is: "+$a_soul
		set match to 0
		set higher to 0
		if a_soul == 6
			let str_soul := "Black"
			set g_count to 0
			set g_soul to 0
			set gem to BlackSoulGem
			let count := Call RomRFnMatchGems gem g_soul
			set g_count to g_count + count
			if g_count > 0
				set match to g_count
			endif
		else
			set g_count to 0
			set g_soul to 0
			;finding matching or higher capacity soul gems
			if a_soul == 1
				let str_soul := "Petty"
				set gem to SoulGemEmpty1Petty
				let count := Call RomRFnMatchGems gem g_soul	
				set g_count to g_count + count
				if g_count > 0
					set match to g_count 
				else
					set gem to SoulGemEmpty2Lesser
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to SoulGemEmpty3Common
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to SoulGemEmpty4Greater
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to SoulGemEmpty5Grand
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to BlackSoulGem
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					if g_count > 0
						set higher to g_count
					endif
				endif
			endif
			if a_soul == 2
				let str_soul := "Lesser"
				set gem to SoulGemEmpty2Lesser
				let count := Call RomRFnMatchGems gem g_soul	
				set g_count to g_count + count
				if g_count > 0
					set match to g_count 
				else
					set gem to SoulGemEmpty3Common
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to SoulGemEmpty4Greater
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to SoulGemEmpty5Grand
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to BlackSoulGem
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					if g_count > 0
						set higher to g_count
					endif
				endif
			endif
			if a_soul == 3
				let str_soul := "Common"
				set gem to SoulGemEmpty3Common
				let count := Call RomRFnMatchGems gem g_soul	
				set g_count to g_count + count
				if g_count > 0
					set match to g_count 
				else
					set gem to SoulGemEmpty4Greater
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to SoulGemEmpty5Grand
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to BlackSoulGem
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					if g_count > 0
						set higher to g_count
					endif
				endif
			endif
			if a_soul == 4
				let str_soul := "Greater"
				set gem to SoulGemEmpty4Greater
				let count := Call RomRFnMatchGems gem g_soul	
				set g_count to g_count + count
				if g_count > 0
					set match to g_count 
				else
					set gem to SoulGemEmpty5Grand
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					set gem to BlackSoulGem
					let count := Call RomRFnMatchGems gem g_soul	
					set g_count to g_count + count
					if g_count > 0
						set higher to g_count
					endif
				endif
			endif			
			if a_soul == 5
				let str_soul := "Grand"
				set gem to SoulGemEmpty5Grand
				let count := Call RomRFnMatchGems gem g_soul	
				set g_count to g_count + count
				set gem to BlackSoulGem
				let count := Call RomRFnMatchGems gem g_soul	
				set g_count to g_count + count
				if g_count > 0
					set match to g_count 
				endif
			endif
		endif
		if match > 0
			print "You have "+$match+" empty "+$str_soul+ " Soul Gem(s) matching this soul."
		elseif higher > 0
			print "You have "+$higher+" empty soul gem(s) with higher capacity, but this would be a waste."
		endif
	endif
	;cleanup
	sv_Destruct str_soul
end

 

 

 

I used both soul checks because there are some exceptions where level check only will give wrong results (for example horses - they have level 1, but lesser soul edited).

Edited by RomanR
Link to comment
Share on other sites

  • Recently Browsing   0 members

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