FlashyJoer Posted January 10, 2018 Share Posted January 10, 2018 Hi all, got a vexing one. I have a blank formlist Ive made in the CK. I have a ref alias that fills in the mod fine. Papyrus adds the ref alias to the formlist and a verification if/notification/endif fragment shows the NPC has been added to the formlist. Now the ref alias has condition IsInList <myformlist> == 0, meaning only select the NPC if they are NOT currently in the formlist. Per wiki: IsInList This function takes a FormList as a parameter and returns 1 if the reference's base object is a member of the FormList or 0 if it is not. My issue is and I am hoping someone can help, even through the ref alias is added to the formlist and my script verifies the added form is present, I fear the form is NULL after the ref alias stops or more precisely, it no longer references the NPC who was supposed to be added. I see behavior that corroborates this because even though a test NPC is added to the list, per my script, on the next fire of the ref alias fill, that same NPC is selected even though, by rights, they shouldnt be. So, I am thinking its due to the ref alias formID is getting added, which is no longer valid once the quest stops, ahead of restarting. Now, Ive wracked my brains trying to get at the actual formid of the NPC and NOT the ref alias to add to the form, but I just cannot figure out how to get there. GetBaseObject is no good as that will just get the Base from the CK and not the world populated NPCs form. I've tried GetLeveledActorBase but it does not seem to want to compile unless I add .getrace, issex, etc, which is not what I want. GetName is no good either, because SETTLER is quite common. So the ask is... HOW do I get the formID of the ACTOR and not the ref alias to add to the formlist? Is this possible? Is it a matter of persistence? I would figure settler NPCs would be persistent anyways, but yes... stumped. ideas / help / solutions? Many thanks! Link to comment Share on other sites More sharing options...
FlashyJoer Posted January 10, 2018 Author Share Posted January 10, 2018 (edited) I should add that GetFormID() is no good either, as you cannot simply add an integer to a formlist according to the compiler. Again, unless I am missing something... Now, if I try this: Actor John = NPCJohn.GetReference() as Actor; this is needed for other functions in my script ObjectReference Johnny = John.GetbaseObject() as ObjectReference AliasFills.AddForm(Johnny) Utility.Wait(0.1) if AliasFills.HasForm(Johnny) Debug.Notification("Johnny added to FormList") endIf It compiles... no clue if it will actually work ingame yet, but I am thinking not due to the whole non-world object reference of Base Object... Edited January 10, 2018 by joerqc Link to comment Share on other sites More sharing options...
FlashyJoer Posted January 10, 2018 Author Share Posted January 10, 2018 (edited) The plot thickens, and I only update this with personal findings for other down the road who may have the same question - my need is still very much relevant. But... if you add an actor to the formlist, you can query the formlist on the papyrus level, ie: I can tell the script to stop the quest with the attached reference alias if the actor is in the formlist via 'If AliasFill.hasForm(Johnny)'. And when I do this, I know have: if aliasfill.hasform(johnny) quest.stop() returnelse aliasfill.addform(johnny)endif So when the NPC approaches me via their attached travel to player package and I interact with them, it adds them to the formlist. When the dialogue terminates, the quest is stopped and the alias flushed. That quest will restart based on a timer and when it does restart, it will NOT select this NPC and will instead, as shown above, just stop the quest and wait for the timer to restart it. Okay, so this works... but - the alias is set to find nearest actor in the loaded cell to the player, so this as a general rule will not work because in this code, it never looks for the next nearest, it simply stops and waits for restart. So I think forms added to a formlist are only accessible from a script level, whereas the IsInList condition on the refalias is looking at the BASE EDITOR level, which is empty as I created an empty formlist. Edited January 10, 2018 by joerqc Link to comment Share on other sites More sharing options...
FlashyJoer Posted January 11, 2018 Author Share Posted January 11, 2018 I believe I will have to go with the scripting solution, which is less than optimal, as the IsInList is definitely looking at the formlist to see if the BASE Object of the form is in the list. Which isnt what I want at all... so, I have come up with an alternate means, by way of a little hackery and I wonder if someone with knowledge of arrays could look at this flow: 1. In NPC approach, they talk to you, I add a keyword to the form and then add them to the formlist.2. Quest stops, restarts and one condition is now to look for the keyword, instead of the formlist. That should work without question for filling the ref alias with someone OTHER than the first NPC who approached. But how to clear the keywords from the forms in the formlist, I asked myself and then I came up with this idea. Using the same timer that I was using to REVERT() the formlist (removing script added forms), I will use an array instead, as follows and this is where I need confirmation that what I am coding will work... Int index = 0 Actor[] ClearList While Index < FL_Approachers.getsize() If FL_Approachers.Find(ClearList[index]) > -1 If ClearList[index].HasKeyword(Approacher_KYWD) ClearList[index].RemoveKeyword(Approacher_KYWD) FL_Approachers.RemoveAddedForm(ClearList[index]) Endif Endif Utility.Wait(0.1) index += 1 Endwhile My hope is that what this does is go through the formlist one index at a time, check the form at index 'x' for a keyword. If present, remove keyword and then remove added form... Wait... if I remove the added form, that will reset the indexes. Best to just remove the keyword and then go to the next index. Once all indexes are exhausted in the formlist and the endwhile finished, thats where I should put the FL_Approachers.Revert() command I think... If noone chimes in, I suppose I will return with results... Link to comment Share on other sites More sharing options...
FlashyJoer Posted January 11, 2018 Author Share Posted January 11, 2018 (edited) While it should in theory work, sadly it appears not to and I have no idea why it is not. Regardless I have now switched from using a formlist to creating an array out of the actors. Actor[] ApproachersReferenceAlias Property ApproachREF auto Event OnInit()Approachers = New Actor[0]Starttimergametime(0.5,1)Endevent Event OnPlayerLoadGame()Starttimergametime(0.5,1)EndEvent OnTimerGameTimer(int TID) If TID == 1 Int index = 0 While Index < Approachers.length Actor Verify = Approachers[index] If Verify.HasKeyword(Approacher_KYWD) Verify.RemoveKeyword(Approacher_KYWD) Endif Utility.Wait(0.1) index += 1 Endwhile Utility.Wait(0.5) Approachers.Clear() Utility.Wait(0.1) StartTimerGameTime(0.5, 10) Endif Endevent {Ref Alias Fill Function} Quest.stop()Quest.start()If Quest.IsRunning() Actor John = ApproachREF.GetReference() as Actor John.AddKeyword(Approacher_KYWD) Approachers.Add(John)Else Debug.trace("Quest did not fill alias")Endif More or less, this is the new hope to add the keyword to the ref alias NPC so that on next ref fill, they will not be chosen until such a time as the game time timer runs out and runs through the array to clear keywords from indexed actors and then flush the array. For those who need to know if THIS works, I will report back... Edited January 11, 2018 by joerqc Link to comment Share on other sites More sharing options...
FlashyJoer Posted January 11, 2018 Author Share Posted January 11, 2018 So... the above code works and works exactly as I was hoping! Leaving this here for future searches... and less hair pulling. Link to comment Share on other sites More sharing options...
Evangela Posted January 11, 2018 Share Posted January 11, 2018 You already know that GetReference() returns the objectreference/actor(depending on the cast type). But you probably didn't know that GetFormID will return Reference ID instead of the FormID unless you do.. GetBaseObject().GetFormID(). So even if you could add FormIDs to a Formlist, you'd be back to the same issue. I believe a FormList will accept only a base form, so yeah, you need to get the base object and add it to the formlist. I don't think you can add an objectreference, or even a leveledactor to a FormList, but my experience with that is limited. I just know that when wanting to do certain things with objectreferences, you're restricted to doing things with them on the "outside" if that makes sense. This is what makes arrays awesome, because they can store every type(but still restricted to 1 type obviously) including ReferenceAliases. So I would suggest you stick with arrays, they are also way faster for the game to process than a formlist. IMO the only advantage a FormList has over an array is it has no limit, but then, the more forms, the LONGER HasForm, GetAt, etc will take to iterate through them. Link to comment Share on other sites More sharing options...
FlashyJoer Posted January 11, 2018 Author Share Posted January 11, 2018 Thanks for the confirmation! :) My only true concern is persistence, but I feel so long as the script is running, which it should as its attached to a quest alias that never stops/restarts, there shouldnt been an issue. I did perform a test with an NPC where they approached, we spoke and then they didnt approach me again, as they had the keyword assigned and thus didnt meet the ref alias fill conditions. I went to Red Rocket (from Sanctaury) and experienced the lull a laptop gives on cell loading - the actor was unload I assumed. But, my debug notices told me on array refresh that actor was in the array and keyword was found and removed. And upon returning to SH, he immediately approached me, so I assume there is persistence due to the script continually running with the actor in the array... At least, that is my hope and takeaway from witnessed events... Link to comment Share on other sites More sharing options...
SMB92 Posted January 13, 2018 Share Posted January 13, 2018 From what I can see, you don't want to be using a formlist for Actors, because getting their Base Object (unless a unique npc) is not really going to happen unless that actor is made persistent (and even then I'm pretty sure there problems). There is also apparently problems with form lists where they drop any variables that aren't persistent (or ck filled) between loads, but I've not tested directly. What's you might want to do, is use a RefCollectionAlias. Then you could add your refs to that directly. It is like an array with the the benefits of an alias. Have a look at this: https://www.creationkit.com/fallout4/index.php?title=RefCollectionAlias_Script If you are also savvy to using the alias, you can add a script that extends actor placed in this alias that will attach to any actor in question added to the collection. Then you can directly add properties to them. You could then setup a relationship between this dynamic actor script and a "master script" on the refalias or even your quest to do further work. Link to comment Share on other sites More sharing options...
subhuman0100 Posted December 13, 2023 Share Posted December 13, 2023 (edited) It's an old one, but someone just referred me to it, so it's apparently still coming up in searches.... So posting a clarification seems like it might end up being useful to others. Caveat: I work with Skyrim. I don't do FO4. That being said, I know why this wouldn't work in Skyrim, and see no reason in this instance to believe the two aren't behaving the same. from OP's post: Quote Per wiki: IsInList This function takes a FormList as a parameter and returns 1 if the reference's base object is a member of the FormList or 0 if it is not. FormLists contain base forms only, hence their name. The condition also is looking at base forms. The base form of an Actor is an ActorBase. i.e. when the condition checks if an actor IsInList, it's looking for that actor's actorbase- not an objectreference! However, the papyrus snippet used to add forms to the formList, cast John (an actor) as Johnny (an objectReference) before adding him. I'm not sure exactly what ends up in the FL in this instance, but it won't be an actorBase. Actor John = NPCJohn.GetReference() as Actor; this is needed for other functions in my script ObjectReference Johnny = John.GetbaseObject() as ObjectReference AliasFills.AddForm(Johnny) Utility.Wait(0.1) if AliasFills.HasForm(Johnny) Debug.Notification("Johnny added to FormList") endIf AliasFills.AddForm(John) probably would have worked, AliasFills.AddForm(John.GetBaseObject() as actorBase) definitely would have Edited December 13, 2023 by subhuman0100 Link to comment Share on other sites More sharing options...
Recommended Posts