Jump to content

2 OBSE array questions (and 2 "General")


hawke1133

Recommended Posts

Greetings all, I am sorry for the long post. (moderators, noob here, forgive my transgressions! lol)

 

I am currently diving into scripting (quests, primarily) and I have run across some problems. I do have some C/C++ (and others) background and I am in need of some general guidance

I have been working on a "scan for NPC_type in current cell" (I have the basics down.)

First OBSE Question:

I am attempting to do a scan and place all the detected NPC_of_type (this example is same faction) into an array for later (next loop through) usage.

How does one go about this?

i.e.

 

scn MyScan

short faction
short refCounter
short counter
short tempCounter
ref tempNPC
array_var refNPC
short range ; a set distance from player. Changeable via quest level.

begin gamemode

let refNPC := ar_contruct Array
let  refCounter:=  GetNumRefs 35 1 1
let tempCounter := refCounter

let tempNPC := Getfirstref 35 1 1

if (tempNPC.faction == player.SameFaction) && (tempNPC.GetDistance Player <range)
  let refNPC [counter] := tempNPC
  let counter +=1
  let tempCounter -=1
endif

while (refCounter !=0)
       let tempNPC := Getnextref
            if (tempNPC.faction == player.SameFaction) && (tempNPC.GetDistance Player <range) ;NPC in same faction and in "range"
               let refNPC [counter] := tempNPC
               let counter +=1
               let refCounter -=1
           endif
loop

end

I know I did not set "range", but it is not part of the problem.

Second OBSE question: Do I need to create multiple arrays for each cell I am in or will a single array set work? (Bad phrasing, I am sorry.)

 

Question 3: If used in a "quest script", will the "time cost" (fps hits) be too costly? (Should I move it to a callable script instead and use an "Onload" detection or some other trigger?)

Question 4: Am I even in the right ballpark (implementation-wise?)

Thank you for all the help, advice.

(Note: Once the "quest" is complete, I know I should delete the arrays and null out the other variables. Or should I?)

Link to comment
Share on other sites

I just realized something I never thought about. I'd always assumed that GetFirstRef and GetNextRef were sort of temporary, as in once you've run out of things for GetNextRef to return, as in the script they're in has run through once, that the next time the script runs it would go through everything again, as though the references have never been returned by GetFirstRef or GetNextRef before.

 

So I can't say whether or not your script would work right (except for the fact that you're using "SameFaction" wrong, and it looks like your tempcounter variable is redundant).

 

For your second question, a single array would work for multiple cells.

 

I don't think the fps hit would be much. I don't even notice any at all when I use it in a script.

 

I'm not sure it matters if you null the variables. It couldn't hurt though.

Link to comment
Share on other sites

Thanks for the glance!

I did a quick test with the code and it CTD's with an OBSE error. (I am using OBSE 20 beta 5) I REM'ed out the main array code and added a message box that prints how many "detected" and the detection routine that I use works. (I know that I did not use the "SameFaction" correctly, but it was the closest thing I could remember to my original code. Since the original esp even killed the CS, I had to restart from scratch. )

 

I will install the latest OBSE 20 (release) and see what happens.

I have a feeling that the array code is what is killing the script/quest/CTD's.

Link to comment
Share on other sites

OK, I did a test and found out my assumption was correct. I made a test script for a quest:

 

 

scn testscript00

array_var actors
ref tempref
ref tempref2
short doOnce
short index
short tempshort

Begin GameMode

if (doOnce == 0)
	let actors := ar_Construct Array
	let doOnce := 1
endif

let tempref := GetFirstRef 69
while (tempref)
	while (tempshort < ar_Size actors)
		let tempref2 := actors [tempshort]
		if (tempref == tempref2)
			Message "An actor which has been referenced before has been detected!"
			StopQuest testquest00
			Break
		endif
		let tempshort := (tempshort + 1)
	loop
	let tempshort := 0
	let actors[index] := tempref
	let tempref := GetNextRef
	let index := (index + 1)
loop

End

 

 

Since the message displayed, that means that every time the script runs, it goes through all the actors again, even ones that have been referenced before. So according to your script, if you stay in an area with 5 NPCs and the script runs a couple of times, then refNPC[0] is the same as refNPC[5], which is the same as refNPC[10], and etc.

Link to comment
Share on other sites

I'm a total script noob (but I'm trying to learn so I follow along with the script type posts). You've probably already caught this (missing a space after refCounter).

let  refCounter:=  GetNumRefs 35 1 1

Link to comment
Share on other sites

Sounds like I need to do a "moved to new cell" test to keep from corrupting the array.

My goal is to get X refID's of type Y, per cell load, add them all to the the array and then manipulate the npc's once per cell (using certain criteria). This routine is supposed to be similar to a "party invite" where members of a certain faction are called to "meet the player".

Your code is excellent, I shall try to add a "bool type" variable for "cell load". (I am starting to get out of my depth here as far as scripting functions. Been cramming, but not enough, it seems.)

 

I shall see if the modifications work correctly.

 

Thank you.

Stryker879, Good catch. I did correct that in the original code, but not before I had pasted it in.

Thanks.

Edited by hawke1133
Link to comment
Share on other sites

My 2 cents on your four questions:

 

1) Pretty much what fg109 said, although I would like to offer a simplified version of the script:

 

scn testscript00 
array_var actors 
ref tempref 

Begin GameMode 
  if GetCellChanged 
     ;=== runs once you enter a new cell ===
     if actors == 0
        let actors := ar_Construct Array 
     endif 

     let tempref := GetFirstRef 69 
     while tempref
        if  <whatever filters you may want to aplly>
           if eval (ar_find tempref actors) < 0
              ;=== Current NPC not in array yet ==
              ar_append actors tempref 
           endif
        endif
        let tempref := GetNextRef 
     loop 
  endif
End

 

2) It actually depends on what you need. I mean, whether or not you need to know in which cell you've met which NPC.

 

3) Array walking is very efficient, but if you walk a large array every frame, you will notice it in the performance. Better look for some way to avoid it, like only once per cell, or every few seconds, if you expect new NPCs to arrive in the current cell.

 

4) Yes

 

5) Yes, when you are done with the array, release it with "Let Actors := ar_Null"

Link to comment
Share on other sites

Actually, the script I posted was for just a test I did. I wasn't sure whether or not GetFirstRef and GetNextRef evaluates all the references in the cell every time it runs, or just the ones it hasn't looked looked at before.

 

But thanks, looking at your script I found the ar_find command. That's definitely useful, and I should probably spend more time looking at the OBSE documentation. :confused:

Link to comment
Share on other sites

3 things and a big thanks to you all! This is the angle I needed.

1. Array walking is what was needed.The procedure I wanted to was this: detect all actors_of_type and add them to the array. In another loop, determine if they were a) in a certain range and b) if they were already talked to. I really don't need to know where I met the NPC (at this time), I only need the array until this quest is completed and just in the current cell.

 

2. I really just needed to detect all actors_of_type once in a new cell and stuff them to the array. Then I would test to see if they are in a certain range and "talked to" in another loop. Thank you QQuix for your code. The GetinSameCell call is what I needed. (Along with the example of array walking.) That is some clean code.

 

3. The array size is not going to be that large. I did a test with my "detection" code game wide and the most I found was 37 NPCs at any time that met my criteria. Since they would not all fall into the "local detection" criteria (need to add a "interior only" test,) I feel that the array size should not be larger than Max<=20. Unless I really have to include the "what cell I met them in", but if that happens, I can always use a couple of more arrays for that and do cell based tests. If that becomes a requirement, then I need to rebuild my original logic flow anyways.

Just a side note to fg109 on on

I wasn't sure whether or not GetFirstRef and GetNextRef evaluates all the references in the cell every time it runs, or just the ones it hasn't looked looked at before.

I figured that the GetFirstRef and GetNextRef would be reinitialized every loop and not keep the original detection.

My thanks to:

fg109

QQuix

and Striker879 for finding my typo! (Keep reading code! That always helps!)

I will post the resulting code when I have everything working. (Soon, I hope)

Link to comment
Share on other sites

GetFirstRef and GetNextRef are designed to be used together within a single run of a single script.

 

GetFirstRef is what resets the search. Whenever you use it, you will start over, no matter what you have done before.

GetNextRef, of course, keeps returning the next reference until (1) there is no more references of that type to return or (2) you reset the process by using GetFirstRef again.

 

If you use them in different scripts (GetFirstRef in one script and GetNextRef on another) or in different frames (GetFirstRef in one frame and GetNextRef in the next) the results are unpredictable, as many other scripts from many other mods may have used them in between.

 

Hope this helps understanding them.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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