Jump to content

Tutorial: Nvse4+ Part 4: Array Variables


Recommended Posts

I have a serious problem with my arrays, and I'm in deep frustration, bc I have no idea how I can fix it.

 

I have 2 arrays, array1 full of base objects, array2 full of values (condition, I can gather those values only once with Inventory references ForEach). Those values are at the same keys as base objects in array1. It looks like this:

DiSCtFtl.jpg

 

And I'm happy with it basically, until I try to sort arrays.

If I will sort array1 by name - I want array2 elements get sorted as well. So, if 9mm Pistol in array1 at key [3.00] after sorting (into array3) is at key [12.0] - I want array2 element at key [3.00] be at key [12.0] (in array4)

So I will have nice alphabetically sorted array3 with base objects and I will be able to access their values at same keys in array4.

Thought about using stringmap, but keys with the same name will not work.

 

Right now I'm thinking about to keep all the info in one array like "[0.00] 9mm Pistol___0.3", sort it, and then loop through that array and sv_split  each element into new array and ar_append new elements into 2 new arrays..  something like that, clearly have no idea if this thing will work at all.

 

update. This thing worked fine

foreach loop
let  SomeString := $Iter + "___" + $Condition
ar_append array1 $SomeString


if nuked == 1
let ArraySorted := ar_sortalpha array1
let iSize := ar_size ArraySorted
set nuked to 2
endif

if nuked == 2
                    if iSize != 0
                                let array2 := sv_split $ArraySorted[0] "___"
                                ar_append array3 array2[0]
                                ar_append array4 array2[1]
                                ar_erase ArraySorted 0
                        set isize to isize -1
                    elseif isize == 0
                        set nuked to 3
                    endif
endif

A little bit slow due to iSize to iSize -1, but at least something =\

Still curious maybe there's a less strange and faster way to achieve what I need.

 

Uptade2

Just realized that I can't access such data as GetBaseDamage from array containing base objects, because they are stings. Oh dear...

Link to comment

There may be other solutions here, but I think maybe you should stick all the intel in a sub-array:

[0][0] := base object 1

[0][1] := condition for the inv ref (I guess)

[1][0] := base object 2

and so on

 

and then sort your primary array with ar_customsort and a UDF that checks sv_compare between the names of the base forms. Either way, base forms & condition stay attached.

Link to comment

There may be other solutions here, but I think maybe you should stick all the intel in a sub-array:

[0][0] := base object 1

[0][1] := condition for the inv ref (I guess)

[1][0] := base object 2

and so on

 

and then sort your primary array with ar_customsort and a UDF that checks sv_compare between the names of the base forms. Either way, base forms & condition stay attached.

 

I have no idea how to, I'm too tired to understand even simple things, but once I get some sleep - I will try. Thank you very much!

Link to comment

It's not the most simple of things, but there's an example in a spoiler in the tutorial.

The ar_customsort function will take 2 elements of the source array (ie. 2 sub-arrays) and compare them. You define how it will decide if subarray a should go before subarray b in your main array by SetFunctionValue 1.

 

so your comparison UDF should be something like

 

scn UDF

 

array_var a

array_var b

 

ref rForm1

ref rForm2

 

Begin Function {a b}

 

let rForm1 := a[0]

let rForm2 := b[0]

if eval 1 == sv_compare $rForm1 $rForm2

    ; the name of rForm1 is alphabetically earlier than the name of rForm2

    SetFunctionValue 1

endif

 

 

End

Link to comment

Yeah, UDF example in tutorial is great, so I understand how it works. And thanks for new comparison for $forms =) The thing I can't get is this:

[0][0] := base object 1

[0][1] := condition for the inv ref (I guess)

 

How can I have an array with [0][0] and [0][1] keys? I'm definitely loosing logic.

Tried something like this.

for array

ar_append array1[0][0] Form
let array1[0][0] := Form

for stringmap

let array1["0"][0] := Form

Obviously, it's not working) I'm doing something very stupid, 100%

Link to comment

well, basically:

let subarray[0] := form

let subarray[1] := number

let mainarray[0] := subarray

 

result

mainarray[0][0] == form

mainarray[0][1] == number

 

giving you nested arrays. Maybe I should make that a bit more explicit in the tutorial.

 

you don't have to 'let' it all manually, just append subarrays to a main array with ar_append, ar_insert or however you go about it

 

edit: the only way a let like this can work:

let mainarray[0][0] := something

is if you already initialized both the main & the sub

Link to comment

Okay, got my rest, feel better now. And little bit confused. Looks like I need new subarray for every new form+number.  Like subarray1, subarray2, subarray3, subarray4, etc. And I will end up with 50+ subarrays =\ That's a good way, but the more items - more subs. Anyway, thank you for your time good sir, I really appreciate your help =3

Link to comment

I still think it's the easiest way to sort the information however you want it (by name, condition etc) while keeping the intel linked.

 

In the end, what you do in your inventory loop ends up with a ref var and a float var for each item, which you now stick in separate arrays.

Instead, I'd just build a subarray with let subarray := ar_list rForm, fFloat, whateverelse

Then ar_append your subarray to your main array. Doesn't really matter how many arrays you build, as long as you can manage them. Another benefit of doing it this way is you can easily attach more information to track, like item type etc, and not change your overall structure much. Whereas separate arrays obviously pose a problem if you start removing, adding, sorting through them, because you need to adjust every array you have to every change you do to any of them.

 

 

 

 

Link to comment
  • 3 weeks later...

Due to the temporary nature of arrays in UDFs, I'm storing an array which contains a list of references on an external quest (which contains all my variables). Anyway I must recreate this list from time to time. Any clue on how I can erase that array var?

 

I explain better what I mean.

- Scan for refs
- ar_append quest.scanner scanned_ref
- loop back
...
- walk my quest.scanner, use ar_size to define its end
...
- DELETE quest.scanner
- re-scan the refs, and walk them again, etc.

if I don't delete the quest.scanner, I risk that ar_append won't start from the first key/index, and also that I will have dirty values if the second scanner scans a smaller number of refs

 

The first idea would be walking the array and Letting it with a not initialized ref var, but... isn't there something easier?

 

EDIT: maybe ar_erase 0:(var defined by ar_size) could be a good idea?

in this case, should it be (var defined by ar_size) or (var defined by ar_size - 1)?

 

Last thing...

When I walk an array, I use a Counter in a While Loop, as condition I use Counter < (var defined by ar_size). While this works, I feel that "Foreach" would the right function to inspect an array, but I can't understand in the tutorial and in NVSE documentation. If it's true, could someone provide an easy example?

Link to comment

The usual way I'd use to delete all elements of an array is just (re)call:

 

let SomeArray := Ar_Construct "Array/Map/StringMap"

 

Which makes the array_var refer to a new empty array, and the old array is deleted if no other var/array points at it.

 

array_var Alpha
array_var Beta
 
let Alpha := Ar_List "cat"
 
let Alpha := Ar_Construct "array"
 
; Alpha refers to a new empty array, and the array that used to store "cat" is automatically deleted
 
let Alpha := Ar_List "cat"
let Beta := Alpha
let Alpha := Ar_Construct "array"
 
; Alpha is empty array
; Beta contains: "cat"

 

You can use 'let SomeArray := Ar_Null' instead, if you want it to point at nothing, instead of an empty initialized array. See also, 'Ar_Resize' and other functions that altar an array in place (they don't return a new array), if you have multiple array_var/elements refering to the same array and want to change that for all of them.

 

foreach is definitely the right way to expect elements in an array, see the GECK page: http://geck.bethsoft.com/index.php?title=Foreach

Link to comment
  • 1 month later...

I've read the whole tutorial and every post.

 

Ar_list can create array with up to 20 elements, I get it.

But how much elements migth array have? (max)

 

 

Can I add via AR_append up to 100 elements? 1000? These elements are supposted to be in array for a couple of seconds

Link to comment
  • 2 months later...

I need to know the key of an array, given the value (if it's present in the array of course). I could create a script that walks the array and compares the value at every step, but I was wondering if there's a proper function that already does it

 

I attach a picture of something that could resemble what I'm looking for

post-165499-0-97707500-1416935031_thumb.jpg

Link to comment
  • 1 month later...

I must run 3 different UDFs which refill an array, basically they will scan 3 different types and fill the same table.

I pass the type as parameter, something like MyUDF 31 means it scans type 31.

 

All these refs must fill the same quest.array, but my problem is I don't know how to append it in the second UDF.

 

Basically, I have a local array and a quest.array, because I can't do this:

ar_append myquest.myarray my_scanned_ref

So instead I do this:

    Let myarray := ar_Construct array
    Let myquest.myarray := myarray
    ar_append myarray my_scanned_ref

And I saw it works fine, it's like if it replicates the quest.array in local. But I can't understand what happen the second time I run the UDF? will the first line (which initializes the local array) destroy the quest.array because of that second line?

Link to comment

Yeah, what you do there is pretty much delete the existing array before populating it again.

 

In cases where I let a UDF populate a quest array var held elsewhere, I just pass it like this:

 

call myUDF quest.arrayvar

 

and capture it like this:

scn myUDF

array_var someVarName ; usually a shorter name than the original

Begin Function {someVarName}

let someVarName[someKey] := someValue
...

End

You can do the same with appending. Of course this means you have to construct the array somewhere else first before you pass it as a parameter to the populating UDF.

Link to comment
  • 3 weeks later...

Changed a few things in the first section about persistence; in general, the rule should be that you explicitly ar_null array vars you don't need anymore instead of relying on the idea that nvse cleans them up once the script has run its course.

Link to comment

I would like to understand when I must unitialize an array.

Could you make some practical examples? for example, I scan a cell and fill an array with references, then I walk the array and do some code with these references. When I change cell I will re-scan the new cell, re-init the array with Ar_construct and fill with the new values: do I need to de-initialized between the first scan and the second one?

Again: I have a bidimensional array with a list of datas. These datas are filled on GGL, but in general they are somewhat persistent datas. Do I need to uninitialize them everytime and then re-fill the array?

If I reset their values with ar_construct, do I still need ar_null?

Link to comment

The fact is, I'm not sure. Some arrays that should be removed by the recycler just handling all arrays that lose a reference, haven't been. I spotted array IDs getting rather high in some spunk logs a while back, and corresponding .nvse files showed what looked like empty arrays being held for no reason I can see. On the whole, it's nothing too serious, I think, but obviously as people use arrays more and more, our practices must adapt until we can find a clearly identifiable cause.

 

Recently I've been adapting spunk to explicitly ar_null arrays if:

- I previously relied on a spell dispelling or a UDF just being done (local vars, including ones I've set to the UDF's function value) to clear things up

- I previously re-let an already established array var to a new array, as in AJ's first example

- they're iterators in foreach loops, which are supposedly uninitialized when the loop is done

 

Obviously not if the whole point of the array is to stick around a while, containing data that I'll need a while.

Not sure which one of those are actually to blame, I just wanted to eliminate every possible cause in my own work.

Link to comment

Let MyArray[0] := MyRef0

Let MyArray[1] := MyRef1

Let MyArray[2] := MyRef2

 

These refs are all in-world.

 

ar_erase MyArray 1 >>> this would erase the key 1.

 

1) What happens to the in world MyRef1 ? is it marked for delete? disabled? unaffected?

2) will MyRef2 take the slot of MyArray[1] ?

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use