Jump to content

How to keep track of a list of NPCs?


DuskWulf

Recommended Posts

I've been banging my head against a wall with this and I'm desperate for help. I'm puttering away at a non-lethal mod but part of it is that I need to clean up 'pacified' NPCs so that they don't behave strangely if the player goes too far from the cell and returns. I want to do Disable and MarkForDelete on the aforementioned pacified NPCs when the player is either away (or has entered a cell and isn't directly looking at them), but I have no way of really tracking them to do so.

 

I tried adding a reference (via GetSelf and GetCrosshairRef) to a form list via AddFormToFormList, but an immediate check afterwards in the script says that the reference wasn't added. Does AddFormToFormList not handle in-game NPC references?

 

I could use ListAddReference, but that won't persist between saves. I could use a faction, that'd be permanent, but I don't know of any way to iterate over every NPC in a faction.

 

Every idea I have seems to come to a dead end.

 

Any help would be vastly appreciated.

 

TL;DR: Essentially, what I need is a permanent way to add a ref to a form list (like ListAddReference does, but permanent, as AddFormToFormList doesn't seem to add the refs), or a way to iterate over every NPC in a given faction.

 

---Edited

 

Thinking I might have to do something like...

Let avActorRefs := GetRefs 200, -1
 
ForEach Elem <- avActorRefs
  Let rActorRef := elem["value"]
  If rActorRef.GetItemCount wulfPacCleanMeUpTok >= 1
    rActorRef.Disable
    rActorRef.MarkForDelete
  EndIf
Loop

I dunno, though... Is there a better way?

Link to comment
Share on other sites

Hey Dusk Wulf,

 

the idea with the faction is actually the way I solved my perk mod.

I am writing on V2.0 of that one to include any base record at start without having to "scan" for references around the player.

Even though that function works either (but may be a bit more of a performance impact than a one-time UDF on startup).

 

This should be preferably a quest script:

scn Whatever

Begin MenuMode 4 ;This will be run only in the main menu
    If GetGameRestarted
        SetBaseFactionRank 0 [YourFriendlyFaction] [base form of NPC]        ;THIS IS A JIP LN function! You need that plugin for.
        ;[...]    The only bad thing with this is that you need to add ANY base form to that faction
    endif
End

Begin GameMode
    ;Later if you get a perk or any condition to make NPCs friendly you can simply change the relations between the [PlayerFaction] and [YourFriendlyFaction]:
    if [FriendCondition = True]
        SetAlly [PlayerFaction] [YourFriendlyFaction] 1 1 ;Makes the factions allies. If you leave the "1 1" away, they will be friends (help you in combat).
    elseif [FriendCondition = False]
        SetEnemy  [PlayerFaction] [YourFriendlyFaction]    1 1 ;This will set them to neutral (initial state). They get hostile again if the other factions in their NPC form doesn't match with the players faction. There is no need to remove the "1 1" in that case, otherwise they will be hostile FOR SURE!
    endif
Endif
Link to comment
Share on other sites

AddFormToFormList should work for an actor ref, so perhaps your way of testing if it was in there wasn't correct. Then again, parking them in an array may be better. For one thing AFTFL adds items to the beginning of the list, which isn't ideal if you're gonna be looping.

 

The best way of handling this very much depends on how large the list can get, and how often you want to check whether to remove ones that aren't around anymore. If the list grows large and you run the loop very often, there's a chance of lag. To avoid that, instead of looping through the whole thing every so often, you can systematically walk through it with each iteration of the quest script, letting that work as your loop instead. And you need to keep in mind that whenever you may need to remove something from any list while inside a loop, that loop has to be done backwards, or you'll skip elements. So here's how I'd do the handling of that:

scn TrackingQstScpt
; attached to TrackingQst

array_var aList
int iKey
ref rRef

Begin GameMode

if eval 1 > ar_size aList ; empty list, no point doing anything
  return
elseif iKey < 1           ; restart the loop from the back
  let iKey := ar_size aList
endif
let iKey -= 1
let rRef := aList[iKey]
; do what you must with rRef

; if you need to remove it, do it here
ar_erase aList, iKey

End 

Ofc, aList needs to be constructed first, which is preferably done in a one-time init somewhere else, or that'd be useless code in a repeating block:

scn InitQstScpt
; attached to InitQst

int iInit

Begin GameMode

if iInit == 0
   let TrackingQst.aList := ar_construct "array"
   startquest TrackingQst
   let iInit := 1
   stopquest InitQst
endif

End

And whenever/however/wherever you detect a ref to be added to the list, you add it like this:

ref rRef  ; could've been gotten from getself/getcrosshairref, whatever

if eval 0 > ar_find rRef, TrackingQst.aList
  ar_append TrackingQst.aList, rRef
endif
Edited by DoctaSax
Link to comment
Share on other sites

  • Recently Browsing   0 members

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