Comparing OBSE arrays

Post » Wed Oct 06, 2010 5:50 pm

As I got suggested in my other thread:

Can you compare two arrays?

Get a "GetEquippedItems" array and store it, and then run a comparison every five seconds with the current array result. If the array is different, you count the number of items (lower indicates the player unequipped something rather than equipped it) and act according to that result.


I want to compare two arrays I get from player.GetEquippedItems (one current frame and one from the previous frame), but I can't get it to work. At the moment my script looks like this :

Spoiler
ScriptName NyczModPlayerEquipWeightScriptfloat fQuestDelayTimeshort doOncearray_var oldItemsbegin GameMode	if doOnce != 1		set fQuestDelayTime to 2		let oldItems := ar_Sort player.GetEquippedItems		set doOnce to 1	endif		; Are they the same size?	; Sort both	; Compare them	; Changed?	short isChanged	short oldLength	short curLength	let oldLength := ar_Size oldItems	let curLength := ar_Size player.GetEquippedItems		PrintC "Old length: %g, Current length: %g" oldLength curLength		if oldLength == curLength		array_var curItems		let curItems := ar_Sort player.GetEquippedItems		short i		ref itm		ref itm2		while i < curLength			let itm := curItems[i]			let itm2 := oldItems[i]			if eval (!(itm.GetIsReference itm2))				set isChanged to 1				break			endif			let i += 1		loop	endif		if isChanged		PrintC "Changed!"	else		PrintC "Unchanged!"	endif		; Last stuff to do:	let oldItems := ar_Sort player.GetEquippedItemsend


I'm not sure if my problem is in the comparison of the arrays or the creation or something else. And I can't find much about this in either the wiki or OBSE docs.
User avatar
STEVI INQUE
 
Posts: 3441
Joined: Thu Nov 02, 2006 8:19 pm

Post » Thu Oct 07, 2010 4:14 am

A couple issues:
All variables must be declared at the start of the script. That also means that you'll need to initialize them to proper values on each run through the script.
GetIsReference works on persistent references, not base objects.

If I may suggest, there's probably a better way to do what you want than by checking if the player's equipped items have changed. Though I don't know what your goal is.
User avatar
zoe
 
Posts: 3298
Joined: Sun Nov 12, 2006 1:09 pm

Post » Thu Oct 07, 2010 3:15 am

What I hope to achieve is to find all equipped items, modify their weigths and finally reset their weights when they get unequipped. Comparing GetEquippedItems arrays seems to be the easiest, at least from what I have seen.

Anyway, I fixed it up following your suggestions. Good thing is that something has changed: If I don't do anything it spams unchanged (which it should). Bad thing is that even if I change clothes while still wearing the same amount of items, it still spams unchanged. I am at a loss :/
Spoiler
ScriptName NyczModPlayerEquipWeightScriptfloat fQuestDelayTimeshort doOnceshort isChangedarray_var oldItemsarray_var curItemsshort oldLengthshort curLengthref item1ref item2short ibegin GameMode	if doOnce != 1		set fQuestDelayTime to 2		let oldItems := ar_Sort player.GetEquippedItems		set doOnce to 1	endif		set isChanged to 0	let oldLength := ar_Size oldItems	let curLength := ar_Size player.GetEquippedItems		PrintC "Old length: %g, Current length: %g" oldLength curLength		if oldLength == curLength		let curItems := ar_Sort player.GetEquippedItems				while i < curLength			let item1 := curItems[i]			let item2 := oldItems[i]			if item1 != item2				set isChanged to 1				break			endif			let i += 1		loop	else		set isChanged to 2	endif		if isChanged == 2		PrintC "Changed in NUMBAAAH!"	elseif isChanged == 1		PrintC "Changed!"	else		PrintC "Unchanged!"	endif		; Last stuff to do:	let oldItems := ar_Sort player.GetEquippedItemsend

User avatar
Music Show
 
Posts: 3512
Joined: Sun Sep 09, 2007 10:53 am

Post » Thu Oct 07, 2010 12:49 am

Before or after your loop you need to set i to 0.
Also, for the sake of (probably minor) efficiency, consider calling player.getEquippedItems and storing it in a local array_var, rather than doing
let curLength := ar_Size player.GetEquippedItems                           ; 1		PrintC "Old length: %g, Current length: %g" oldLength curLength		if oldLength == curLength		let curItems := ar_Sort player.GetEquippedItems                      ; 2;snip	; Last stuff to do:	let oldItems := ar_Sort player.GetEquippedItems                              ; 3

You're calling it 3 times where you only need to call it once - each time you call the command OBSE has to go through the entire inventory to locate equipped items. Given a significantly crowded inventory this can produce a potentially noticeable delay. Regardless, it's wholly unnecessary. (There would also be no reason to sort it twice).

Finally, be aware that when you modify the weights of equipped items you will also modify the weights of any unequipped versions of those items in the player's inventory. Dunno if that matters for your purposes or not.

EDIT regarding array comparison: array1 == array2 is true only if both array variables refer to the same array. It compares array IDs, not contents. (Similar to object identity in typical object-oriented languages).
User avatar
JESSE
 
Posts: 3404
Joined: Mon Jul 16, 2007 4:55 am

Post » Wed Oct 06, 2010 10:29 pm

Before or after your loop you need to set i to 0.

Whoops xD Silly little mistake.

Finally, be aware that when you modify the weights of equipped items you will also modify the weights of any unequipped versions of those items in the player's inventory. Dunno if that matters for your purposes or not.

Only modifying weight of the whole type? That would not work very well at alll... The best would be if it was possible to either change the weight of a single reference or somehow dynamically clone the item into a new type with modified (zero) weight.
Otherwise I can only think of pretty ugly hacks to get it to work (another item taking up the weight of the non-equipped items)

EDIT regarding array comparison: array1 == array2 is true only if both array variables refer to the same array. It compares array IDs, not contents. (Similar to object identity in typical object-oriented languages).

Yeah, I thought as much. Comparing them straight off was mostly a wild hope (and to be sure).


EDIT: Well at least now it seems to work, thanks. :) Half done, half to go.

Spoiler
ScriptName NyczModPlayerEquipWeightScriptfloat fQuestDelayTimeshort doOnceshort isChangedarray_var oldItemsarray_var curItemsshort oldLengthshort curLengthref item1ref item2short ibegin GameMode	let curItems := ar_Sort player.GetEquippedItems	if doOnce != 1		set fQuestDelayTime to 2		let oldItems := curItems		set doOnce to 1	endif		set isChanged to 0	let oldLength := ar_Size oldItems	let curLength := ar_Size curItems		PrintC "Old length: %g, Current length: %g" oldLength curLength		if oldLength == curLength		set i to 0		while i < curLength			let item1 := curItems[i]			let item2 := oldItems[i]			if item1 != item2				set isChanged to 1				break			endif			let i += 1		loop	else		set isChanged to 2	endif		if isChanged == 2		PrintC "Changed in NUMBAAAH!"	elseif isChanged == 1		PrintC "Changed!"	else		PrintC "Unchanged!"	endif		; Last stuff to do:	let oldItems := curItemsend

User avatar
Shiarra Curtis
 
Posts: 3393
Joined: Thu Jan 04, 2007 3:22 pm

Post » Thu Oct 07, 2010 6:08 am

Only modifying weight of the whole type? That would not work very well at alll... The best would be if it was possible to either change the weight of a single reference or somehow dynamically clone the item into a new type with modified (zero) weight.
Otherwise I can only think of pretty ugly hacks to get it to work (another item taking up the weight of the non-equipped items)

Only base objects have weight so modifying a single reference isn't possible. Cloning is an option (but I'd put it in the 'ugly hacks' category). A possibly less ugly hack would be to figure out what the total weight of the equipped and unequipped items should be, then set the weight to their average; e.g. if you wanted that equipped items always weigh 1/2 their normal weight:
let weight := getweight itemlet num := getitemcount itemlet weight := weight*(num-1) + weight/2let weight /= numsetweight weight item

User avatar
Rik Douglas
 
Posts: 3385
Joined: Sat Jul 07, 2007 1:40 pm


Return to IV - Oblivion