-
Posts
640 -
Joined
-
Last visited
Content Type
Profiles
Forums
Events
Posts posted by ReDragon2013
-
-
version 9 like Sphered gave us the hint. https://www.creationkit.com/index.php?title=GetNthSpell_-_Actor
;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ; https://github.com/powerof3/PapyrusExtenderSSE/tree/master/src/Papyrus ;Import StorageUtil ; https://github.com/Vicyntae/SCLSE/blob/master/Data/Source/Scripts/StorageUtil.psc ; StorageUtil name: "HAC_Spells" ; list of strings, names of spells the player has currently ; StorageUtil name: "map" ; list of strings as keyname to formID as value ; used in MCM script with StorageUtil.GetFormValue(None, (StorageUtil.StringListGet(None, "HAC_Spells", INDEX+1))) Bool bRefresh ; [default=False] ; -- Events -- 3 + "Refresh" Event OnInit() ; called first time mod will be seen on game (newgame or savegame) InitList() EndEvent Event OnPlayerLoadGame() ; called every time a mod was loaded by savegame (player alias script only!) InitList() EndEvent Event OnSpellLearned(Spell akSpell) ; added by Papyrus Extender SSE While ( bRefresh ) Utility.Wait(0.1) ; just in case, do not allow another thread to sneak in to an update in progress EndWhile bRefresh = TRUE ; *T* StorageUtil.StringListRemoveAt(None, "HAC_Spells", 0) ; remove the escape menu, before adding a new spell to stringlist Update_HAC_Spells(akSpell) ; add this spell to stringlist InsertMenu_HAC_Spells() ; insert the escape menu bRefresh = False ; *** EndEvent ;====================================== State Refresh ;============ Function InitList() ; empty here, OnInit() or OnPlayerLoadGame() event can be the first ("first come, first serve") EndFunction Event OnUpdate() If ( bRefresh ) RETURN ; - STOP - Just in case! EndIf ; ------------------------ bRefresh = TRUE ; *T* PO3_Events_Alias.UnRegisterForSpellLearned(self) ; unregister for the special event Debug.Notification("HAC: Starting Spell Maintenance") CreateSpellList() InsertMenu_HAC_Spells() ; Insert the escape menu gotoState("") ; ### STATE ### Debug.Notification("HAC: Spell Maintenance Completed") PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event bRefresh = False ; *** EndEvent ;======= endState ; -- Functions -- 4 Function InitList() ;-------- 1 gotoState("Refresh") ; ### STATE ### RegisterForSingleUpdate(1.0) EndFunction Function Update_HAC_Spells(Spell akSpell) ;-------- 2 string s = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction Function InsertMenu_HAC_Spells() ;-------- 3 StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the stringlist before insert the menu entry! ; Insert to stringlist at index 0 an escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") EndFunction Function CreateSpellList() ;-------- 4 actor player = Game.GetPlayer() string s StorageUtil.StringlistClear(None, "HAC_Spells") ; *** clear *** ; https://www.creationkit.com/index.php?title=GetSpellCount_-_Actor ; https://www.creationkit.com/index.php?title=GetNthSpell_-_Actor int i = player.GetSpellCount() While (i) i = i - 1 spell akSpell = player.GetNthSpell(i) ; GetNthSpell(0) is the last added spell s = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist EndWhile EndFunction
About version 8:
you wrote: "The one script gets assigned to the ref alias, I'm assuming I just attach the other two to the quest in CK?"
Yes, its70_PlayerAliasScript has to be attached to PlayerAlias in your quest.
No, the other two scripts put in as source files in the right papyrus directory.
its70_PlayerAliasGlobal.psc
its70_PlayerAliasScriptExtender.psc
So the CK can find it for compiling. Normaly all three scripts should be compiled, if you compile the its70_PlayerAliasScript script with CK.
I edited my post for version 8 as well!
-
Like Sphered wrote anything to reduce the spell array entries and is fast in runtime would speed up your stringlist creation.
You wrote: "And I can't for the life of me figure out why....."
Not every script change is always the way in the right direction. As you know "Trial and Error" is the way to go.
So I was thinking about my theory in version 6 and 7 and come to this.
version 8 consists of 3 scripts
its70_PlayerAliasGlobal
Scriptname its70_PlayerAliasGlobal Hidden {v8.0 ReD, 2022-02-12} ; this is our toolbox, a script without self ; -- FUNCTIONs -- 2 Function Update_HAC_SG(Actor player, Spell akSpell) Global If player.HasSpell(akSpell) Update_HAC(akSpell) EndIF EndFunction Function Update_HAC(Spell akSpell) Global string s = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction
its70_PlayerAliasScriptExtender
Scriptname its70_PlayerAliasScriptExtender extends ReferenceAlias {v8.0 ReD, 2022-02-12} ; this is the main extender script our parent, "DO NOT ASSIGN to an ALIAS" !!! ;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ; https://github.com/powerof3/PapyrusExtenderSSE/tree/master/src/Papyrus ;Import StorageUtil ; https://github.com/Vicyntae/SCLSE/blob/master/Data/Source/Scripts/StorageUtil.psc ; StorageUtil name: "HAC_Spells" ; list of strings, names of spells the player has currently ; StorageUtil name: "map" ; list of strings as keyname to formID as value ; used in MCM script with StorageUtil.GetFormValue(None, (StorageUtil.StringListGet(None, "HAC_Spells", INDEX+1))) ;------------------------------------------------------------------------------------------------------------------------------------------------------- Bool PROPERTY bRefresh auto Hidden ; [default=False] Spell[] PROPERTY a auto Hidden Function InitArray() a = PO3_SKSEFunctions.GetAllSpells() EndFunction Function DestroyArray() spell[] b a = b ; make array script variable unassigned EndFunction Int iFlag ; [default=0] Function UpdateFlag() ; helper iFlag = iFlag - 1 EndFunction ; -- Events -- ;====================================== State Refresh ;============ Function InitList() ; empty here, OnInit() or OnPlayerLoadGame() event can be the first ("first come, first serve") EndFunction Event OnUpdate() If ( bRefresh ) RETURN ; - STOP - Just in case! EndIf ; ------------------------ bRefresh = TRUE ; *T* PO3_Events_Alias.UnRegisterForSpellLearned(self) ; unregister for the special event Debug.Notification("HAC: Starting Spell Maintenance") InitArray() ; Build array with all spells ingame StorageUtil.StringlistClear(None, "HAC_Spells") ; *** clear *** ; ----- iFlag = 2 ; prepare for count of threads, that running now gotoState("Threading") ; ### STATE ### see child script RegisterForSingleUpdateGameTime(0.0) CreateSpellList() ; ** 1 ** build new storageutil stringlist UpdateFlag() WHILE (iFlag) ; iFlag != 0 Utility.Wait(0.1) ; wait until both threads have finished the loop ENDWHILE ; ----- DestroyArray() ; clean up the spell array InsertMenu_HAC_Spells() ; Insert the escape menu gotoState("") ; ### STATE ### Debug.Notification("HAC: Spell Maintenance Completed") PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event bRefresh = False ; *** EndEvent ;======= endState ; -- Functions -- 3 + 3 + (1) = 7 ;------------------------------- Function InsertMenu_HAC_Spells() ; helper ;------------------------------- StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the stringlist before insert the menu entry! ; insert to stringlist at index 0 an escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") EndFunction ;---------------------------------------- Function Update_HAC_Spells(Spell akSpell) ; helper ;---------------------------------------- string s = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction ;------------------------- Function CreateSpellList() ;------------------------- actor player = Game.GetPlayer() int i = a.Length + 1 ; 100+1 If (i < 2) RETURN ; - STOP - empty array /or/ one element only EndIF While (i > 0) i = i - 2 ; a[99], a[97], .. ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If a[i].GetNthEffectMagicEffect(0).GetCastingType() its70_PlayerAliasGlobal.Update_HAC_SG(player, a[i]) ; see "its70_PlayerAliasGlobal.psc", function EndIf EndWhile EndFunction
its70_PlayerAliasScript
Scriptname its70_PlayerAliasScript extends its70_PlayerAliasScriptExtender {v8.0 ReD, 2022-02-12} ; this is the script, which has to be assigned to the player alias ; ------------ ; -- Events -- 3 + "Threading" ; ------------ Event OnInit() ; called first time mod will be seen on game (newgame or savegame) InitList() EndEvent Event OnPlayerLoadGame() ; called every time a mod was loaded by savegame (player alias script only!) InitList() EndEvent Event OnSpellLearned(Spell akSpell) ; added by Papyrus Extender SSE While ( bRefresh ) Utility.Wait(0.1) ; just in case, do not allow another thread to sneak in to an update in progress EndWhile bRefresh = TRUE ; *T* StorageUtil.StringListRemoveAt(None, "HAC_Spells", 0) ; remove the escape menu, before adding a new spell to stringlist Update_HAC_Spells(akSpell) ; add this spell to stringlist InsertMenu_HAC_Spells() ; insert the escape menu bRefresh = False ; *** EndEvent ;=============================== State Threading ;============== Function InitList() ; empty here, OnInit() or OnPlayerLoadGame() event can be the first ("first come, first serve") EndFunction EVENT OnUpdateGameTime() CreateSpellList2() ; ** 2 ** build new storageutil stringlist UpdateFlag() ; see parent script "its70_PlayerAliasScriptExtender.psc" ENDEVENT ;======= endState ; -- FUNCTIONs -- (5) + 2 = 7 ;------------------ Function InitList() ;------------------ gotoState("Refresh") ; ### STATE ### see parent script "its70_PlayerAliasScriptExtender.psc", OnUpdate() RegisterForSingleUpdate(1.0) EndFunction ;------------------------------- Function CreateSpellList2(Int i) ;------------------------------- actor player = Game.GetPlayer() int i = a.Length ; 100 If (i == 0) RETURN ; - STOP - empty array EndIF If (i == 1) i = i + 1 ; adjust to get a[0] EndIf While (i > 0) i = i - 2 ; a[98], a[96], .. ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If a[i].GetNthEffectMagicEffect(0).GetCastingType() its70_PlayerAliasGlobal.Update_HAC_SG(player, a[i]) ; see "its70_PlayerAliasGlobal.psc" EndIf EndWhile EndFunction
-
I changed the code from version 6 and add to the same posting of mine version 7.
-
I do not have any experience with skyui event management.
suggestion version 6a
;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ; https://github.com/powerof3/PapyrusExtenderSSE/tree/master/src/Papyrus ;Import StorageUtil ; https://github.com/Vicyntae/SCLSE/blob/master/Data/Source/Scripts/StorageUtil.psc ; StorageUtil name: "HAC_Spells" ; list of strings, names of spells the player has currently ; StorageUtil name: "map" ; list of strings as keyname to formID as value ; used in MCM script with StorageUtil.GetFormValue(None, (StorageUtil.StringListGet(None, "HAC_Spells", INDEX+1))) Bool bRefresh ; [default=False] ; ------------ ; -- Events -- 3 + "Refresh" ; ------------ Event OnInit() ; called first time mod will be seen on game (newgame or savegame) InitList() EndEvent Event OnPlayerLoadGame() ; called every time a mod was loaded by savegame (player alias script only!) InitList() EndEvent Event OnSpellLearned(Spell akSpell) ; added by Papyrus Extender SSE While ( bRefresh ) Utility.Wait(0.1) ; just in case, do not allow another thread to sneak in to an update in progress EndWhile bRefresh = TRUE ; *T* StorageUtil.StringListRemoveAt(None, "HAC_Spells", 0) ; remove the escape menu, before adding a new spell to stringlist Update_HAC_Spells(akSpell) ; add this spell to stringlist InsertMenu_HAC_Spells() ; insert the escape menu bRefresh = False ; *** EndEvent ;====================================== State Refresh ;============ Function InitList() ; empty here, OnInit() or OnPlayerLoadGame() event can be the first ("first come, first serve") EndFunction Event OnUpdate() If ( bRefresh ) RETURN ; - STOP - Just in case! EndIf ; ------------------------ bRefresh = TRUE ; *T* PO3_Events_Alias.UnRegisterForSpellLearned(self) ; unregister for the special event Debug.Notification("HAC: Starting Spell Maintenance") InitArray() ; Build array with all spells ingame StorageUtil.StringlistClear(None, "HAC_Spells") ; *** clear *** iFlag = 2 ; prepare for two threads running now RegisterForSingleUpdateGameTime(0.0) CreateSpellList() ; ** 1 ** build new storageutil stringlist WHILE (iFlag) ; iFlag != 0 Utility.Wait(0.1) ; wait until both threads have finished the loop ENDWHILE DestroyArray() ; clean up the spell array InsertMenu_HAC_Spells() ; Insert the escape menu gotoState("") ; ### STATE ### Debug.Notification("HAC: Spell Maintenance Completed") PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event bRefresh = False ; *** EndEvent Event OnUpdateGameTime() CreateSpellList2() ; ** 2 ** build new storageutil stringlist EndEvent ;======= endState ; --------------- ; -- Functions -- 1 + 5 + 2 = 8 ; --------------- Function InitList() gotoState("Refresh") ; ### STATE ### RegisterForSingleUpdate(1.0) EndFunction ;------------------------------------------------------------------------------------------------------------------- Int iFlag Function UpdateFlag() ; helper iFlag = iFlag - 1 EndFunction Spell[] a Function InitArray() a = PO3_SKSEFunctions.GetAllSpells() EndFunction Function DestroyArray() spell[] b a = b ; make array variable "a" unassigned s = "" ; clear string s2 = "" ; clear string EndFunction Function CreateSpellList() ; OnUpdate() actor player = Game.GetPlayer() int i = a.Length + 1 ; 100 + 1 = 101 99 + 1 = 100 While (i > 0) i = i - 2 ; a[99], a[97], .., a[3], a[1] a[98], a[96], .., a[4], a[2], a[0] ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If a[i].GetNthEffectMagicEffect(0).GetCastingType() If player.HasSpell( a[i] ) ; check spell from array to see if the player knows or not Update_HAC_Spells( a[i] ) EndIf EndIf EndWhile UpdateFlag() EndFunction Function CreateSpellList2() ; OnUpdateGameTime() actor player = Game.GetPlayer() int i = a.Length ; 100 99 While (i > 0) i = i - 2 ; a[98], a[96], .., a[2], a[0] a[97], a[95], .., a[3], a[1] ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If a[i].GetNthEffectMagicEffect(0).GetCastingType() If player.HasSpell( a[i] ) ; check spell from array to see if the player knows or not Update_HAC_Spells2( a[i] ) EndIf EndIf EndWhile UpdateFlag() EndFunction ;------------------------------------------------------------------------------------------------------------------- ; use a script variable instead of function variable to avoid initial memory cost each time of calling next function String s String s2 Function Update_HAC_Spells(Spell akSpell) ; helper s = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction Function Update_HAC_Spells2(Spell akSpell) ; helper s2 = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s2, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s2, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction Function InsertMenu_HAC_Spells() ; helper StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the stringlist before insert the menu entry! ; insert to stringlist at index 0 an escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") EndFunction
What is new?
Try to get speed up by using two threads to create the final stringlist, required more conditions, more code and more script variables
Be warned it's an approach, not fully tested! In theory we could run three threads at time without using "futures or callbacks". https://www.creationkit.com/index.php?title=Creating_Multithreaded_Skyrim_Mods
suggestion version 7 required some debugging to calculate the right counter conditions for the loops !!
;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ; https://github.com/powerof3/PapyrusExtenderSSE/tree/master/src/Papyrus ;Import StorageUtil ; https://github.com/Vicyntae/SCLSE/blob/master/Data/Source/Scripts/StorageUtil.psc ; StorageUtil name: "HAC_Spells" ; list of strings, names of spells the player has currently ; StorageUtil name: "map" ; list of strings as keyname to formID as value ; used in MCM script with StorageUtil.GetFormValue(None, (StorageUtil.StringListGet(None, "HAC_Spells", INDEX+1))) Bool bRefresh ; [default=False] ; ------------ ; -- Events -- 3 + "Refresh" ; ------------ Event OnInit() ; called first time mod will be seen on game (newgame or savegame) InitList() EndEvent Event OnPlayerLoadGame() ; called every time a mod was loaded by savegame (player alias script only!) InitList() EndEvent Event OnSpellLearned(Spell akSpell) ; added by Papyrus Extender SSE While ( bRefresh ) Utility.Wait(0.1) ; just in case, do not allow another thread to sneak in to an update in progress EndWhile bRefresh = TRUE ; *T* StorageUtil.StringListRemoveAt(None, "HAC_Spells", 0) ; remove the escape menu, before adding a new spell to stringlist Update_HAC_Spells(akSpell) ; add this spell to stringlist InsertMenu_HAC_Spells() ; insert the escape menu bRefresh = False ; *** EndEvent ;====================================== State Refresh ;============ Function InitList() ; empty here, OnInit() or OnPlayerLoadGame() event can be the first ("first come, first serve") EndFunction Event OnUpdate() If ( bRefresh ) RETURN ; - STOP - Just in case! EndIf ; ------------------------ bRefresh = TRUE ; *T* PO3_Events_Alias.UnRegisterForSpellLearned(self) ; unregister for the special event Debug.Notification("HAC: Starting Spell Maintenance") InitArray() ; Build array with all spells ingame StorageUtil.StringlistClear(None, "HAC_Spells") ; *** clear *** iFlag = 3 ; prepare for three threads running now gotoState("Threading") ; ### STATE ### RegisterForSingleUpdateGameTime(0.0) RegisterForSingleUpdate(0.0) CreateSpellList() ; ** 1 ** build new storageutil stringlist WHILE (iFlag) ; iFlag != 0 Utility.Wait(0.1) ; wait until all threads have finished the loop ENDWHILE DestroyArray() ; clean up the spell array InsertMenu_HAC_Spells() ; Insert the escape menu gotoState("") ; ### STATE ### Debug.Notification("HAC: Spell Maintenance Completed") PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event bRefresh = False ; *** EndEvent ;======= endState ;====================================== State Threading ;============== Function InitList() ; empty here, OnInit() or OnPlayerLoadGame() event can be the first ("first come, first serve") EndFunction Event OnUpdateGameTime() CreateSpellList2() ; ** 2 ** build new storageutil stringlist EndEvent Event OnUpdate() CreateSpellList3() ; ** 3 ** build new storageutil stringlist EndEvent ;======= endState ; --------------- ; -- Functions -- 1 + 6 + 4 = 11 ; --------------- Function InitList() gotoState("Refresh") ; ### STATE ### RegisterForSingleUpdate(1.0) EndFunction ;------------------------------------------------------------------------------------------------------------------- Int iFlag Function UpdateFlag() ; helper iFlag = iFlag - 1 EndFunction Spell[] a Function InitArray() a = PO3_SKSEFunctions.GetAllSpells() EndFunction Function DestroyArray() spell[] b a = b ; make array variable "a" unassigned EndFunction Function CreateSpellList() ; first thread actor player = Game.GetPlayer() int i = (a.Length / 3) + 1 ; 100 -> a[33] .. a[0] While (i) i = i - 1 ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If a[i].GetNthEffectMagicEffect(0).GetCastingType() If player.HasSpell( a[i] ) ; check spell from array to see if the player knows or not Update_HAC_Spells( a[i] ) EndIf EndIf EndWhile UpdateFlag() EndFunction Function CreateSpellList2() ; 2nd thread - OnUpdateGameTime() actor player = Game.GetPlayer() int m = a.Length / 3 int i = a.Length - m + 1 ; 100 -> a[66] .. a[34] While (i > m) i = i - 1 ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If a[i].GetNthEffectMagicEffect(0).GetCastingType() If player.HasSpell( a[i] ) ; check spell from array to see if the player knows or not Update_HAC_Spells2( a[i] ) EndIf EndIf EndWhile UpdateFlag() EndFunction Function CreateSpellList3() ; 3rd thread - OnUpdate() actor player = Game.GetPlayer() int i = a.Length ; 100 -> a[99] .. a[67] int m = i - (i / 3) While (i > m) i = i - 1 ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If a[i].GetNthEffectMagicEffect(0).GetCastingType() If player.HasSpell( a[i] ) ; check spell from array to see if the player knows or not Update_HAC_Spells2( a[i] ) EndIf EndIf EndWhile UpdateFlag() EndFunction ;------------------------------------------------------------------------------------------------------------------- ; use a script variable instead of function variable to avoid initial memory cost each time of calling next function String s String s2 String s3 Function Update_HAC_Spells(Spell akSpell) ; helper s = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction Function Update_HAC_Spells2(Spell akSpell) ; helper s2 = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s2, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s2, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction Function Update_HAC_Spells3(Spell akSpell) ; helper s3 = akSpell.GetName() ; get the spell name as string StorageUtil.SetFormValue(None, s3, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s3, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction Function InsertMenu_HAC_Spells() ; helper ; clear each script variable s = "" s2 = "" s3 = "" StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the stringlist before insert the menu entry! ; insert to stringlist at index 0 an escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") EndFunction
-
suggestion version 5
;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ; https://github.com/powerof3/PapyrusExtenderSSE/tree/master/src/Papyrus ;Import StorageUtil ; https://github.com/Vicyntae/SCLSE/blob/master/Data/Source/Scripts/StorageUtil.psc ; StorageUtil name: "HAC_Spells" ; list of strings, names of spells the player has currently ; StorageUtil name: "map" ; list of strings as keyname to formID as value ; used in MCM script with StorageUtil.GetFormValue(None, (StorageUtil.StringListGet(None, "HAC_Spells", INDEX+1))) Bool bRefresh ; [default=False] ; ------------ ; -- Events -- 4 ; ------------ Event OnInit() ; called first time mod will be seen on game (newgame or savegame) RegisterForSingleUpdate(1.0) EndEvent Event OnPlayerLoadGame() ; called every time a mod was loaded by savegame (player alias script only!) RegisterForSingleUpdate(1.0) EndEvent Event OnUpdate() If ( bRefresh ) RETURN ; - STOP - Do not allow multiple threads at same time! EndIf ; ------------------------ bRefresh = TRUE ; *T* PO3_Events_Alias.UnRegisterForSpellLearned(self) ; unregister for the special event Debug.Notification("HAC: Starting Spell Maintenance") CreateSpellList() ; Clear storageutil stringlist and build it new StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the stringlist. InsertMenu_HAC_Spells() ; Insert the escape menu Debug.Notification("HAC: Spell Maintenance Completed") PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event bRefresh = False ; *** EndEvent Event OnSpellLearned(Spell akSpell) ; added by Papyrus Extender SSE WHILE ( bRefresh ) Utility.Wait(0.1) ; just in case, do not allow another thread to sneak in to an update in progress ENDWHILE bRefresh = TRUE ; *T* StorageUtil.StringListRemoveAt(None, "HAC_Spells", 0) ; remove the escape menu, before adding a new spell to stringlist Update_HAC_Spells(akSpell) ; add this spell to stringlist StorageUtil.StringListSort(None, "HAC_Spells") ; sort the stringlist (of final output player known spell names) InsertMenu_HAC_Spells() ; insert the escape menu bRefresh = False ; *** EndEvent ; --------------- ; -- Functions -- 3 ; --------------- ; use a script variable instead of function variable to avoid initial memory cost each time of calling next function String s Function Update_HAC_Spells(Spell akSpell) ; helper ; get the first effect of the spell and give back the casting type (0..2) ; 0 = constant effect (not desired to add into stringlist) ; 1 = Fire and Forget ; 2 = Concentration If akSpell.GetNthEffectMagicEffect(0).GetCastingType() s = akSpell.GetName() ; get name of spell StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE Endif EndFunction Function InsertMenu_HAC_Spells() ; helper ; insert at index 0 of sorted stringlist an escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") EndFunction Function CreateSpellList() actor player = self.GetActorReference() ; for this kind of script its the same as "actor player = Game.GetPlayer()" spell[] a = PO3_SKSEFunctions.GetAllSpells() ; Build a temp array with all spells in the game StorageUtil.StringlistClear(None, "HAC_Spells") ; *** clear *** strings int i = a.Length While (i) ; (i != 0) i = i - 1 If player.HasSpell( a[i] ) ; check spell from array to see if the player knows it or not Update_HAC_Spells( a[i] ) EndIf EndWhile EndFunction
What is new?
- OnSpellLearned() got own thread handling
- You should try, if its useful to make "string s" as script variable instead of function variable!
- The conditions in main loop has been changed. Maybe useful for speed up!
-
as Sphered wrote:
this code
int i i = i + 1
do the same as next code
int i i += 1
BUT, what is better to understand? Keep in mind there is no different in papyrus executable script. wiki link: https://www.creationkit.com/index.php?title=Statement_Reference
version 3 for code optimization
;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ;Import StorageUtil ; StorageUtil name: "HAC_Spells" ; list of strings ; StorageUtil name: "HAC_SpForms" ; list of forms ;------------------------------------------------------------- Bool bRefresh ; [default=False] ; -- EVENTs -- 4 EVENT OnInit() ; called first time mod will be seen on game (newgame or savegame) RegisterForSingleUpdate(1.0) ENDEVENT EVENT OnPlayerLoadGame() ; called every time a mod was loaded by savegame (player alias script only!) RegisterForSingleUpdate(1.0) ENDEVENT EVENT OnUpdate() IF ( bRefresh ) RETURN ; - STOP - Do not allow multiple threads at same time! ENDIF ;--------------------- bRefresh = TRUE ; *T* PO3_Events_Alias.UnRegisterForSpellLearned() Debug.Notification("HAC: Starting Spell Maintenance") CreateSpellList() ; Clear storageutil stringlist and add new spell strings StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the final output player spell names stringlist. Strings_To_Forms() ; Clear storageutil list of spell forms and add new forms Debug.Notification("HAC: Spell Maintenance Completed") PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event bRefresh = False ; *** ENDEVENT EVENT OnSpellLearned(Spell akSpell) ; event added by Papyrus Script Extender WHILE (bRefresh) Utility.Wait(0.1) ; wait here until main refresh is finished ENDWHILE Update_HAC_Spells(akSpell) ; add the spell to storageutil stringlist ; remove existing escape menu from stringlist before sorting StorageUtil.StringListRemove(None, "HAC_Spells", "Back / Cancel / No Change", True) StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the stringlist of player spell names to output on screen. Strings_To_Forms() ; Clear storageutil list of spell forms and add new forms ENDEVENT ; -- FUNCTIONs -- 3 Function Update_HAC_Spells(Spell akSpell) ; helper string s = akSpell.GetName() StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction Function CreateSpellList() ; helper actor player = Game.GetPlayer() spell[] a = PO3_SKSEFunctions.GetAllSpells() ; Build a temp array with all spells in the game StorageUtil.StringlistClear(None, "HAC_Spells") ; *** clear *** strings int i = a.Length WHILE (i) ; (i != 0) i = i - 1 spell akSpell = a[i] ; get the first MagicEffect of valid spell and give back the casting type (0..2) IF (akSpell) && akSpell.GetNthEffectMagicEffect(0).GetCastingType() ; 1 = Fire and Forget, 2 = Concentration IF player.HasSpell(akSpell) ; check the playable spell from array to see, if the player has it Update_HAC_Spells(akSpell) ENDIF ENDIF ENDWHILE EndFunction Function Strings_To_Forms() ; helper int m = StorageUtil.StringListCount(None, "HAC_Spells") ; get length of stringlist StorageUtil.FormListClear(None, "HAC_SpForms") ; *** clear *** forms ; use the sorted stringlist to build the store the same a formlist (without escape menu) int i = 0 WHILE (i < m) form fm = StorageUtil.GetFormValue(None, StorageUtil.StringListGet(None, "HAC_Spells", i)) IF ( fm ) StorageUtil.FormListAdd(None, "HAC_SpForms", fm) ENDIF i = i + 1 ENDWHILE ; insert at index 0 of stringlist the escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") EndFunction
version 4 for studying, it is creating the formlist first and the stringlist after
;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ; https://www.nexusmods.com/skyrimspecialedition/mods/22854?tab=files&BH=0 ; https://github.com/powerof3/PapyrusExtenderSSE/tree/master/src/Papyrus ;Import StorageUtil ; StorageUtil name: "HAC_Spells" ; list of strings, will be sorted by script on every spell update ; StorageUtil name: "HAC_SpForms" ; list of forms, keeps unsorted ;------------------------------------------------------------------------------------------------------------- Bool bRefresh ; [default=False] ; -- EVENTs -- 4 EVENT OnInit() ; called first time mod will be seen on game (newgame or savegame) ;=========== 1 RegisterForSingleUpdate(1.0) ENDEVENT EVENT OnPlayerLoadGame() ; called every time a mod was loaded by savegame (player alias script only!) ;===================== 2 RegisterForSingleUpdate(1.0) ENDEVENT EVENT OnUpdate() ;============= 3 IF ( bRefresh ) RETURN ; - STOP - Do not allow multiple threads at same time! ENDIF ;--------------------- bRefresh = TRUE ; *T* PO3_Events_Alias.UnRegisterForSpellLearned(self) ; unregister for special event Debug.Notification("HAC: Starting Spell Maintenance") ; ### debug info ### CreateFormList() ; Clear storageutil formlist and add all player spells Forms_To_Strings() ; Clear storageutil stringlist and build it new ;--- ; Sort the final output player spell names stringlist. StorageUtil.StringListSort(None, "HAC_Spells") ; insert at index 0 of stringlist the escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") ;--- Debug.Notification("HAC: Spell Maintenance Completed") ; ### debug info ### PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event bRefresh = False ; *** ENDEVENT EVENT OnSpellLearned(Spell akSpell) ; event added by powerofthrees Papyrus Extender ;=================== 4 WHILE (bRefresh) Utility.Wait(0.1) ; wait here until main refresh is finished, just in case ENDWHILE StorageUtil.FormListAdd(None, "HAC_SpForms", akSpell as Form, False) StorageUtil.StringListRemoveAt(None, "HAC_Spells", 0) ; remove the escape menu from stringlist before adding a new spell Update_HAC_Spells(akSpell) ; add this spell to storageutil stringlist ;--- ; Sort the final output player spell names stringlist. StorageUtil.StringListSort(None, "HAC_Spells") ; insert at index 0 of stringlist the escape menu as way out StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") ;--- ENDEVENT ; -- FUNCTIONs -- 3 ;---------------------------------------- Function Update_HAC_Spells(Spell akSpell) ; helper ;---------------------------------------- string s = akSpell.GetName() StorageUtil.SetFormValue(None, s, akSpell as Form) ; Make sure that the spell name string is mapped to the correct formid StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; Add a new spell name to stringlist with allowdupes == FALSE EndFunction ;------------------------ Function CreateFormList() ;------------------------ actor player = Game.GetPlayer() spell[] a = PO3_SKSEFunctions.GetAllSpells() ; Build a temp array with all spells in the game StorageUtil.FormListClear(None, "HAC_SpForms") ; *** clear *** forms int i = a.Length ; <array>.Length returns always a value greater or equal to ZERO WHILE (i) ; (i) is equal to (i != 0) i = i - 1 spell akSpell = a[i] ; get the first MagicEffect of valid spell and give back the casting type (0..2) IF (akSpell) && akSpell.GetNthEffectMagicEffect(0).GetCastingType() ; 1 = Fire and Forget, 2 = Concentration IF player.HasSpell(akSpell) ; check the playable spell from array to see, if the player has it StorageUtil.FormListAdd(None, "HAC_SpForms", akSpell as Form, False) ; do not allow duplicates in list ENDIF ENDIF ENDWHILE EndFunction ;-------------------------- Function Forms_To_Strings() ;-------------------------- int m = StorageUtil.FormListCount(None, "HAC_SpForms") ; get length of unsorted formlist ;;; StorageUtil.FormListClear(None, "HAC_Spells") ; *** clear *** spells , removed this line, because of wrong function! StorageUtil.StringListClear(None, "HAC_Spells") ; *** clear *** spells ; use the formlist of spells to build a new stringlist of spellnames int i = 0 WHILE (i < m) spell akSpell = StorageUtil.GetFormValue(None, StorageUtil.FormListGet(None, "HAC_SpForms", i)) as Spell IF ( akSpell ) Update_HAC_Spells(akSpell) i = i + 1 ELSE StorageUtil.FormListRemoveAt(None, "HAC_SpForms", i) m = m - 1 ENDIF ENDWHILE EndFunction
-
(1) Keep in mind: If I rewrite the papyrus code I thought something about it. My version do the same, but is faster code.
If (akSpell) && akSpell.GetNthEffectMagicEffect(0).GetCastingType() ; get the first MagicEffect of the spell
your version
If (akSpell) && akSpell.GetNthEffectMagicEffect(0).GetCastingType() > 0 ; get the first MagicEffect of the spell
(2) about event handling, try this:
;Import PO3_Events_Alias ;Import PO3_SKSEFunctions ;Import StorageUtil ; StorageUtil name: "HAC_Spells" ; list of strings ; StorageUtil name: "HAC_SpForms" ; list of forms ; -- EVENTs -- 4 EVENT OnInit() ; called first time mod will be seen on game (newgame or savegame) RegisterForSingleUpdate(1.0) ENDEVENT EVENT OnPlayerLoadGame() ; called every time mod was loaded by savegame RegisterForSingleUpdate(1.0) ENDEVENT EVENT OnUpdate() Debug.Notification("HAC: Starting Spell Maintenance") RefreshAllSpells() Debug.Notification("HAC: Spell Maintenance Completed") PO3_Events_Alias.RegisterForSpellLearned(self) ; register for special event ENDEVENT EVENT OnSpellLearned(Spell akSpell) ; event added by Papyrus Script Extender AddTo_HAC_Spells(akSpell) ; add the spell to storageutil stringlist StorageUtil.StringListSort(None, "HAC_Spells") ; Sort the final output spell names stringlist. Strings_To_Forms() ; Clear storageutil list of spell forms and add new forms ENDEVENT
(3) Its surely faster to store only one formlist like "HAC_SpForms" and create a temporary Stringlist like "HAC_Spells" on th fly, if its recomended by MCM menu. But without to see code dependencies its a hint only.
-
IA710 wrote: "Any suggestions are welcome."
Maybe you remember to an older MCM posting, I wrote similiar 'use functions to separate code and reduce redundancy'.
I think the use of "HAC_PlSpellForms" does not make sense. Link to storageutil papyrus source: https://github.com/Vicyntae/SCLSE/blob/master/Data/Source/Scripts/StorageUtil.psc
My optimizations as follow:
; PapyrusUtil name: "HAC_Spells" ; list of strings ; PapyrusUtil name: "HAC_SpForms" ; list of forms EVENT OnSpellLearned(Spell akSpell) ; event added by Papyrus Script Extender ;=================== ; add the spell to storageutil stringlist myF_AddTo_HAC_Spells(akSpell) ; Sort the final output spell names stringlist. StorageUtil.StringListSort(None, "HAC_Spells") ; Clear storageutil list of spell forms and add new forms myF_Strings_To_Forms() ENDEVENT ;------------------------------------------- FUNCTION myF_AddTo_HAC_Spells(Spell akSpell) ; helper ;------------------------------------------- string s = akSpell.GetName() ; Make sure that the spell name string is mapped to the correct formid StorageUtil.SetFormValue(None, s, akSpell as Form) ; Remove index 0 of the final output stringlist StorageUtil.StringListShift(None, "HAC_Spells") ; Add the spell name to the final output stringlist with allowdupes FALSE StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ENDFUNCTION ;-------------------------- FUNCTION RefreshAllSpells() ;-------------------------- ; Clear storageutil stringlist and add new spell strings myF_CreateSpellList() ; Sort the final output player spell names stringlist. StorageUtil.StringListSort(None, "HAC_Spells") ; Clear storageutil list of spell forms and add new forms myF_Strings_To_Forms() ENDFUNCTION ;-------------------------------------------- FUNCTION myF_Update_HAC_Spells(Spell akSpell) ; helper ;-------------------------------------------- string s = akSpell.GetName() ; get the name and use storageutil functions StorageUtil.SetFormValue(None, s, akSpell as Form) ; convert formid value of the spell as string:formid map StorageUtil.StringListAdd(None, "HAC_Spells", s, False) ; add spellname to stringlist ENDFUNCTION ;----------------------------- FUNCTION myF_CreateSpellList() ; helper ;----------------------------- actor player = Game.GetPlayer() StorageUtil.StringlistClear(None, "HAC_Spells") ; *** clear *** strings ; Build an array with all spells in the game spell[] a = PO3_SKSEFunctions.GetAllSpells() int i = a.Length ; a = allSpellsInTheGame WHILE (i) i = i - 1 spell akSpell = a[i] IF (akSpell) && akSpell.GetNthEffectMagicEffect(0).GetCastingType() ; get the first MagicEffect of the spell ; 1 = Fire and Forget ; 2 = Concentration ; check every playable spell from master list to see if the player has it IF player.HasSpell(akSpell) myF_Update_HAC_Spells(akSpell) ENDIF ;;; ELSE ; 0 = constant effect, we are not interested in this spell ENDIF ENDWHILE ENDFUNCTION ;------------------------------ FUNCTION myF_Strings_To_Forms() ; helper ;------------------------------ int m = StorageUtil.StringListCount(none, "HAC_Spells") StorageUtil.FormListClear(None, "HAC_SpForms") ; *** clear *** forms ; using the sorted string list to build the final output player spell formlist int i = 0 WHILE (i < m) form fm = StorageUtil.GetFormValue(none, StorageUtil.StringListGet(None, "HAC_Spells", i) ) IF ( fm ) StorageUtil.FormListAdd(None, "HAC_SpForms", fm) ENDIF i = i + 1 ENDWHILE ; insert at index 0 of sorted stringlist an escape menu as backdoor StorageUtil.StringListInsert(None, "HAC_Spells", 0, "Back / Cancel / No Change") ENDFUNCTION
-
Hmm.. to get them work you have to change the script from extending objectReference into actor (I edited my previous posting)!
But that is out of "good coding practice" for the player or any other unique vanilla actor.
https://www.creationkit.com/index.php?title=OnObjectEquipped_-_Actor
So we have to change the whole script as follow.
https://www.creationkit.com/index.php?title=OnEquipped_-_ObjectReference
colo_FluidAnimationScript v2
Scriptname colo_FluidAnimationScript extends ObjectReference ; https://forums.nexusmods.com/index.php?/topic/10877768-help-with-scripting/ ; version 2 Idle PROPERTY IdleStop_Loose auto ; added 2022-01-31, missing in older post ; -- EVENTs -- 2 + "Waiting" + "WearItem" EVENT OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer) IF (akNewContainer == Game.GetPlayer() as ObjectReference) gotoState("Waiting") ; ### STATE ### player got the item, observe equip now ELSE UnRegisterForUpdate() ; just in case gotoState("") ; ### STATE ### ENDIF ENDEVENT EVENT OnUpdate() Game.GetPlayer().PlayIdle(IdleStop_Loose) ; after 20 sec the item is wearing, play vanilla stop animation Utility.Wait(0.1) ENDEVENT ;=================================== State Waiting ;============ EVENT OnEquipped(Actor akActor) gotoState("WearItem") ; ### STATE ### myF_Action(1) RegisterForSingleUpdate(20.0) ; wait for 20 sec ENDEVENT ;======= endState ;=================================== State WearItem ;============= EVENT OnUnEquipped(Actor akActor) UnRegisterForUpdate() gotoState("Waiting") ; ### STATE ### myF_Action(0) ENDEVENT ;======= endState ; -- FUNCTION -- ;------------------------- FUNCTION myF_Action(Int i) ;------------------------- IF ( i ) ; i == 1 Debug.SendAnimationEvent(Game.GetPlayer(), "EFF") ; if item equipped play special animation ELSE ; i == 0 Debug.SendAnimationEvent(Game.GetPlayer(), "EFFstop") ; if item will be un-equipped play special stop animation ENDIF ENDFUNCTION
-
or this way by using google search "skyrim OSA"
you'll find https://www.nexusmods.com/skyrim/mods/76744?tab=files
download the archive: OSA-Plus Preview 1 -
(1) you wrote: "I'm VERY NEW to scripting."
Well.. a reason, but no thank you or any other good sign of you. I am really disappointed, in older days your postings were called "script kiddies"!
original scriptnames
DF_Script_Trophy_Base.psc DF_Script_Trophy_Misc.psc DF_Script_Trophy_Activator.psc
my scriptnames
wilw_Trophy_Base.psc wilw_Trophy_Misc.psc wilw_Trophy_Activator.psc
(oRef as wilw_Trophy_Activator).myF_Init(i) ; <-- By changing script name adjust here !!!
your scriptnames
cg_Trophy_Base.psc cg_Trophy_Misc.psc cg_Trophy_Activator.psc
(oRef as cg_Trophy_Activator).myF_Init(i) ; <-- By changing script name adjust here !!!
(2) you wrote: "how do i make a spoiler tag"
Did you have a brain? If yes, use an internet web searcher or the forum search function (right on top).
[ spoiler ]
hidden posting, to make it work remove the spaces within the brackets
[ /spoiler ]
-
DF_Script_Trophy_Activator
Scriptname DF_Script_Trophy_Activator extends ObjectReference {This script deletes the trophy being activated and sets its global back to 0.} ;Original script created by Darkfox127 ;Any potential problems which may arise from this script being changed from the original are the sole responsibility of the mod author making the changes. GlobalVariable Property Global_Trophy_Placed_01 Auto {The trophy global for the trophy base to know if a trophy is already in place.} GlobalVariable Property Global_Trophy_Placed_02 Auto {The trophy global for the trophy base to know if a trophy is already in place.} Int Property XPos_TrophyMarker_01 Auto {The X axis position of the X-Marker used for the first trophy base.} Int Property XPos_TrophyMarker_02 Auto {The X axis position of the X-Marker used for the second trophy base.} LeveledItem Property Trophy_Craft_Items Auto {A leveled list containing all of the items used for creating the trophy.} ObjectReference Property PlayerREF Auto {The default reference for the game to point toward the player.} String Property ReturnMSG Auto {The notification to show when the craft items have been returned to the player.} Event OnActivate(ObjectReference akActionRef) If (Self.GetPositionX() == XPos_TrophyMarker_01) Global_Trophy_Placed_01.SetValue(0) ;Set the trophy global to 0 to allow the base to know a new trophy can be placed ElseIf (Self.GetPositionX() == XPos_TrophyMarker_02) Global_Trophy_Placed_02.SetValue(0) ;Set the trophy global to 0 to allow the base to know a new trophy can be placed EndIf PlayerREF.AddItem(Trophy_Craft_Items, 1, True) ;Silently give the player all of the items back which were used in this trophys creation debug.notification(ReturnMSG) ;Show a notification to inform the player their items have been returned to them Self.delete() ;The trophy now deletes itself and is no longer visible on the trophy base, allowing for a new trophy to be put down EndEvent
wilw_Trophy_Activator
Scriptname wilw_Trophy_Activator extends ObjectReference {v1.0 ReD 2022-01-21} ; This script deletes the trophy being activated and sets its global back to 0. ; https://www.nexusmods.com/skyrim/mods/79519?tab=files ; "Ressource Pack" made by Darkfox127 ; Original created by Darkfox127 ; Any potential problems which may arise from this script being changed from the ; original are the sole responsibility of the mod author making the changes. ;------------------------------------------------------------------------------- LeveledItem PROPERTY Trophy_Craft_Items auto ; A leveled list containing all of the items used for creating the trophy. String PROPERTY ReturnMSG = "You got all trophy items back!" auto ; {The notification to show when the craft items have been returned to the player.} ; ----------------------------------------------------- ;;Int Property XPos_TrophyMarker_01 Auto ; {The X axis position of the X-Marker used for the first trophy base.} ;;Int Property XPos_TrophyMarker_02 Auto ; {The X axis position of the X-Marker used for the second trophy base.} ; v1 ;;GlobalVariable PROPERTY Global_Trophy_Placed_01 Auto ; {The trophy global for the trophy base to know if a trophy is already in place.} ;;GlobalVariable PROPERTY Global_Trophy_Placed_02 Auto ; {The trophy global for the trophy base to know if a trophy is already in place.} ;; .. ;;GlobalVariable PROPERTY Global_Trophy_Placed_21 Auto ; {The trophy global for the trophy base to know if a trophy is already in place.} ; v2 GlobalVariable[] PROPERTY Array_Global_Trophy_Placed auto ; array of Globals pre-placed by CreationKit ; Array_Global_Trophy_Placed[0] = Global_Trophy_Placed_01 ; .. ; Array_Global_Trophy_Placed[20] = Global_Trophy_Placed_21 ; next properties will be set during runtime GlobalVariable PROPERTY Global_Trophy_Placed auto Hidden ; {The trophy global for the trophy base to know if a trophy is already in place.} ; -- EVENTs -- (3 of 3) EVENT OnInit() ;; Debug.Trace(" OnInit() - has been reached.. " +self) ; for debugging only ENDEVENT EVENT OnActivate(ObjectReference akActionRef) IF (akActionRef == Game.GetPlayer() as ObjectReference) ELSE RETURN ; - STOP - not player activated! ENDIF ;--------------------- self.Disable(TRUE) ; fade it out ; silently give the player all of the items back, which were used in this creation of trophy. akActionRef.AddItem(Trophy_Craft_Items as Form, 1, TRUE) ; all goods/materials back to player ; set the trophy global to 0 to allow the base to know a new trophy can be placed Global_Trophy_Placed.SetValue(0.0) Debug.Notification(ReturnMSG) ; inform the player, that trophy material items have been returned to the inventory ; The trophy now deletes itself and is no longer visible on the trophy base, allowing for a new trophy to be put down self.Delete() ENDEVENT ; -- FUNCTION -- ;----------------------- FUNCTION myF_Init(Int i) ; v2, external called by "wilw_Trophy_Misc.psc" ;----------------------- IF (i >= 0) && (i < Array_Global_Trophy_Placed.Length) Global_Trophy_Placed = Array_Global_Trophy_Placed[i] Global_Trophy_Placed.SetValue(1.0) ELSE Debug.Trace(" myF_Init() - Error: array index is out of bound! " +i) ENDIF ; now destroy the array of globalVars, no longer needed! GlobalVariable[] b Array_Global_Trophy_Placed = b ENDFUNCTION ;;----------------------- ;FUNCTION myF_Init(Int i) ; v1, external called by "wilw_Trophy_Misc.psc" ;;----------------------- ; IF (i == 1) ; Global_Trophy_Placed = Global_Trophy_Placed_01 ; ELSEIF (i == 2) ; Global_Trophy_Placed = Global_Trophy_Placed_02 ; ; .. ; ; ELSEIF (i == 21) ; Global_Trophy_Placed = Global_Trophy_Placed_21 ; ENDIF ; ; Global_Trophy_Placed.SetValue(1.0) ;ENDFUNCTION
Advantage you do not have to deal with a lot of "X axis position of the X-Marker".
-
Sometimes its a good idea to use spoiler tags and its always fine to post a link where to find the original scripts. Keep it in mind!
mod: "Ressource Pack" made by Darkfox127 https://www.nexusmods.com/skyrim/mods/79519?tab=files
video: "Creation Kit (Custom Trophy Stands)", How to create multiple trophies? https://www.youtube.com/watch?v=-4igxAUcJ3AThe trophy creation is using next three scripts.
1 - DF_Script_Trophy_Base.psc 2 - DF_Script_Trophy_Misc.psc 3 - DF_Script_Trophy_Activator.psc
At first do not use the scriptnames (from above) provided by ressource pack. Make it unique enough like next:
wilw_Trophy_Base.psc wilw_Trophy_Misc.psc wilw_Trophy_Activator.psc
Now I changed the original scripts in some code parts to make it easier to handle. You have to use an array and also to create a formlist.
DF_Script_Trophy_Base
Scriptname DF_Script_Trophy_Base extends ObjectReference {Checks if a trophy is in place. If there is no trophy in place, this allows the player to add one.} ;Original script created by Darkfox127 ;Any potential problems which may arise from this script being changed from the original are the sole responsibility of the mod author making the changes. GlobalVariable Property Global_Trophy_Placed Auto {DEFAULT: 0 This will be set to 1 once a trophy is placed to allow this base to know if a trophy is in place.} GlobalVariable Property Global_Trophy_Active Auto {This will allow the crafting menu to know which base to place the trophy on.} Int Property Int_Trophy_Tag Auto {Which trophy stand you want this trophy base to control.} String Property FailMSG Auto {The message you want to display if the player activates this base and a trophy is already in place.} Event OnActivate(ObjectReference akActionRef) If (Global_Trophy_Placed.GetValue() == 1) ;Is a trophy already in place? debug.notification(FailMSG) ;Inform the player they cannot add a trophy is one is already in place Else Global_Trophy_Active.SetValue(Int_Trophy_Tag) ;The trophy base you are going to be adding a trophy to Utility.Wait(0.1) ;Short delay to allow global changes to take effect Self.GetLinkedRef().Activate(Game.GetPlayer()) ;Activates the craft system that your linked ref should point to EndIf EndEvent
wilw_Trophy_Base
Scriptname wilw_Trophy_Base extends ObjectReference {v1.0 ReD 2022-01-21} ; check if a trophy is in place. If there is no trophy in place, this allows the player to add one. ; https://www.nexusmods.com/skyrim/mods/79519?tab=files ; "Ressource Pack" made by Darkfox127 ; https://www.youtube.com/watch?v=-4igxAUcJ3A ; "Creation Kit (Custom Trophy Stands)", How to create multiple trophies? ; 1 "DF_Script_Trophy_Base.psc" ; 2 "DF_Script_Trophy_Misc.psc" ; 3 "DF_Script_Trophy_Activator.psc" ; Original created by Darkfox127 ; Any potential problems which may arise from this script being changed from the ; original are the sole responsibility of the mod author making the changes. ;------------------------------------------------------------------------------- GlobalVariable PROPERTY Global_Trophy_Active auto ; global.GetValue() is 0.0 by default ; This will be set to a value of Trophy_Tag, which allows the "crafting menu" to know the base to place the trophy on. Int PROPERTY Int_Trophy_Tag auto ; [default=0], {Which trophy stand you want this trophy base to control.} ; 1 ; 2 ; .. ; 21 GlobalVariable PROPERTY Global_Trophy_Placed auto ; This globalVar will be set by "DF_Script_Trophy_Activator.psc" to a value of 1.0 ; Global_Trophy_Placed_01 ; once a trophy is placed to allow this base to know if the trophy is in place. ; Global_Trophy_Placed_02 ; .. ; Global_Trophy_Placed_21 String PROPERTY FailMSG = "Trophy already placed!" auto ; {The message you want to display if the player activates this base and a trophy is already in place.} ; -- EVENTs -- (1 of 3) EVENT OnActivate(ObjectReference akActionRef) myF_Action(akActionRef) ENDEVENT ; -- FUNCTION -- ;----------------------------------------------- FUNCTION myF_Action(ObjectReference akActionRef) ;----------------------------------------------- IF (akActionRef == Game.GetPlayer() as ObjectReference) ELSE RETURN ; - STOP - /1 not player activated! ENDIF ;--------------------- IF (Global_Trophy_Placed.GetValueInt() == 1) Debug.Notification(FailMSG) RETURN ; - STOP - /2 you cannot add another trophy here, its already in place. ENDIF ;--------------------- IF (Int_Trophy_Tag <= 0) Debug.Notification("Illegal trophy tag.. " +Int_Trophy_Tag) RETURN ; - STOP - /3 ENDIF ;--------------------- Global_Trophy_Active.SetValueInt( Int_Trophy_Tag ) ; The trophy base you are going to be adding a trophy to Utility.Wait(0.1) ; Short delay to allow global changes to take effect ; at least we have to activate the craft system that your linkedRef should point to self.GetLinkedRef().Activate(akActionRef) ENDFUNCTION
DF_Script_Trophy_Misc
Scriptname DF_Script_Trophy_Misc extends ObjectReference {This script creates a trophy and places it on the trophy base currently being activated.} ;Original script created by Darkfox127 ;Any potential problems which may arise from this script being changed from the original are the sole responsibility of the mod author making the changes. Activator Property Trophy_To_Place Auto {The trophy to create and place on the base.} GlobalVariable Property Global_Trophy_Active Auto {This will check to see which trophy base is currently set to active so that this craft menu knows where to place the trophy.} GlobalVariable Property Global_Trophy_InUse Auto {A global which is set after crafting an item to prevent the player from creating more than one trophy on the same stand.} GlobalVariable Property Global_Trophy_Placed_01 Auto {The trophy global for the trophy base to know if a trophy is already in place.} GlobalVariable Property Global_Trophy_Placed_02 Auto {The trophy global for the trophy base to know if a trophy is already in place.} MiscObject Property Trophy_Item Auto {This is the item created by the crafting menu which triggers these events. This is the item this script is attached to.} ObjectReference Property TrophyMarker_01 Auto {This will be one of the X-Marker Headings that your trophy is placed on.} ObjectReference Property TrophyMarker_02 Auto {This will be one of the X-Marker Headings that your trophy is placed on.} ObjectReference Property PlayerREF Auto {The default reference for the game to point toward the player.} Event OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer) If (Global_Trophy_Active.GetValue() == 0) ;Is the current base tagged as 0? debug.notification("Global Set Wrong") ElseIf (Global_Trophy_Active.GetValue() == 1) ;Is the current base tagged as 1? TrophyMarker_01.PlaceAtMe(Trophy_To_Place) ;Place the trophy at the relevant marker Global_Trophy_Placed_01.Setvalue(1) ;Set base one as trophy placed PlayerREF.RemoveItem(Trophy_Item,1,True) ; Removes the trophy misc item from the players inventory silently ElseIf (Global_Trophy_Active.GetValue() == 2) ;Is the current base tagged as 1? TrophyMarker_02.PlaceAtMe(Trophy_To_Place) ;Place the trophy at the relevant marker Global_Trophy_Placed_02.Setvalue(1) ;Set base two as trophy placed PlayerREF.RemoveItem(Trophy_Item,1,True) ; Removes the trophy misc item from the players inventory silently EndIf Global_Trophy_InUse.SetValue(1) Utility.Wait(0.1) Global_Trophy_InUse.SetValue(0) EndEvent
wilw_Trophy_Misc
Scriptname wilw_Trophy_Misc extends ObjectReference {v1.0 ReD 2022-01-21} ; This script creates a trophy and places it on the trophy base currently being activated. ; https://www.nexusmods.com/skyrim/mods/79519?tab=files ; "Ressource Pack" made by Darkfox127 ; Original created by Darkfox127 ; Any potential problems which may arise from this script being changed from the ; original are the sole responsibility of the mod author making the changes. ;------------------------------------------------------------------------------- GlobalVariable PROPERTY Global_Trophy_InUse auto ; global.GetValue() is 0.0 by default ; after crafting an item, prevent the player from creating more than one trophy on the same stand. GlobalVariable PROPERTY Global_Trophy_Active auto ; value was already set by "DF_Script_Trophy_Base.psc" ; This will check to see which trophy base is currently set to active so that this craft menu knows where to place the trophy. Activator PROPERTY Trophy_To_Place auto ; to create a new object which has attached "DF_Script_Trophy_Activator.psc" ; The trophy to create and place at right position. MiscObject PROPERTY Trophy_Item auto ; I am the item created by the crafting menu which triggers these events. {This is the baseObject this script is attached to.} ; ----------------------------------------------------- ;;GlobalVariable PROPERTY Global_Trophy_Placed_01 auto ; {The trophy global for the trophy base to know if a trophy is already in place.} ;;GlobalVariable PROPERTY Global_Trophy_Placed_02 auto ; {The trophy global for the trophy base to know if a trophy is already in place.} ; v1 ;;ObjectReference PROPERTY TrophyMarker_01 auto ; {This will be one of the X-Marker Headings that your trophy is placed on.} ;;ObjectReference PROPERTY TrophyMarker_02 auto ; {This will be one of the X-Marker Headings that your trophy is placed on.} ;; .. ;;ObjectReference PROPERTY TrophyMarker_21 auto ; {This will be one of the X-Marker Headings that your trophy is placed on.} ; v2a ;;ObjectReference[] PROPERTY Array_TrophyMarkers auto ; array of TrophyMarkers pre-placed by CreationKit ; Array_TrophyMarkers[0] = TrophyMarker_01 ; .. ; Array_TrophyMarkers[20] = TrophyMarker_21 ; v2b FormList PROPERTY TrophyMarkerList auto ; you have to create the formlist by CreationKit and assign to this property as well ; TrophyMarkerList.GetAt(0) = TrophyMarker_01 ; .. ; TrophyMarkerList.GetAt(20) = TrophyMarker_21 ; -- EVENTs -- (2 of 3) EVENT OnInit() ;; Debug.Trace(" OnInit() - has been reached.. " +self) ; for debugging only ENDEVENT EVENT OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer) IF myF_IsOK(akNewContainer) Global_Trophy_InUse.SetValue(1.0) Utility.Wait(0.1) Global_Trophy_InUse.SetValue(0.0) ENDIF ENDEVENT ; -- FUNCTIONs -- 2 ;----------------------------------------------------- Bool FUNCTION myF_IsOK(ObjectReference akNewContainer) ;----------------------------------------------------- IF (akNewContainer == Game.GetPlayer() as ObjectReference) ELSE Return False ; /1 its not the players inventory ENDIF ;--------- int i = Global_Trophy_Active.GetValueInt() IF (i == 0) Debug.Notification("Trophy is not active.. GlobalVar setting is wrong!") Return False ; /2 ENDIF ;--------- ; v1 ; IF (i == 1) ; myF_Place(TrophyMarker_01, i) ; ELSEIF (i == 2) ; myF_Place(TrophyMarker_02, i) ; ENDIF ; v2a, v2b myF_Place(akNewContainer, i) Return TRUE ; /3 trophy successful placed ENDFUNCTION ;-------------------------------------------------------- FUNCTION myF_Place(ObjectReference akNewContainer, Int i) ; v2 ;-------------------------------------------------------- ; silently remove the trophy misc item from players inventory akNewContainer.RemoveItem(Trophy_Item as Form, 1, TRUE) ; place a trophy at the relevant marker i = i - 1 ; adjust start position ;; objectReference oRef = Array_TrophyMarkers[i] ; get the marker from array objectReference oRef = TrophyMarkerList.GetAt(i) as ObjectReference ; get the marker by formlist IF ( oRef ) oRef = oRef.PlaceAtMe(Trophy_To_Place as Form, 1) ; place a new object "the trophy" depends on this misc item IF ( oRef ) (oRef as wilw_Trophy_Activator).myF_Init(i) ; <-- By changing script name adjust here !!! ELSE Debug.Notification("Failed to place the trophy!") ENDIF ELSE Debug.Notification("Failed to get a valid trophy marker!") ENDIF ENDFUNCTION ;;---------------------------------------------- ;FUNCTION myF_Place(ObjectReference oRef, Int i) ; v1 ;;---------------------------------------------- ;; silently remove the trophy misc item from players inventory ; Game.GetPlayer().RemoveItem(Trophy_Item as Form, 1, TRUE) ; ;; place a trophy at the relevant marker ; oRef = oRef.PlaceAtMe(Trophy_To_Place as Form, 1) ; IF ( oRef ) ; (oRef as wilw_Trophy_Activator).myF_Init(i) ; <-- By changing script name adjust here !!! ; ELSE ; Debug.Notification("Failed to place the trophy!") ; ENDIF ;ENDFUNCTION
-
As Sphered already mentioned: What ever you do, do never use x, y or z as variable or property names within scripts of type objectreference!
Its caused by vanilla script "ObjectReference.psc", so the papyrus compiler handles x as self.X etc.
Scriptname ObjectReference extends Form Hidden ; Property to obtain the current X position of the object float Property X float Function get() return GetPositionX() EndFunction EndProperty ; Property to obtain the current Y position of the object float Property Y float Function get() return GetPositionY() EndFunction EndProperty ; Property to obtain the current Z position of the object float Property Z float Function get() return GetPositionZ() EndFunction EndProperty
-
while (i >= 0) ;;; Schedule = BB_ActiveSchedules.GetAt(0) As Quest ; you code line quest q = BB_ActiveSchedules.GetAt(i) As Quest referenceAlias RA = q.GetAlias(0) As ReferenceAlias IF ( RA ) RA.Clear() ENDIF i = i - 1 endwhile
just another approach by using array
https://forums.nexusmods.com/index.php?/topic/10976043-defined-property-returning-as-none/ GlobalVariable PROPERTY AtLocation auto ObjectReference PROPERTY MapMarker auto FormList PROPERTY ScheduleQuests auto Quest[] BB_ActiveSchedules Bool bBusy ; [default=False] FUNCTION InitArray() ;------------------- BB_ActiveSchedules = new Quest[100] ENDFUNCTION FUNCTION DestroyArray() ;---------------------- quest[] b BB_ActiveSchedules = b ENDFUNCTION ;------------------------ FUNCTION BB_SetSchedule() ;------------------------ WHILE (bBusy) Utility.Wait(0.1) ENDWHILE bBusy = TRUE ; ------- quest q = ScheduleQuests.GetAt( AtLocation.GetValueInt() ) as Quest ; get the schedule quest referenceAlias RA = q.GetAlias(0) as ReferenceAlias ; get related alias IF ( RA ) RA.ForceRefTo(MapMarker) ; refer to marker ENDIF IF (BB_ActiveSchedules.Length == 0) InitArray() ENDIF int i = BB_ActiveSchedules.Find(None) IF (i >= 0) BB_ActiveSchedules[i] = q ; store to array as active quest ENDIF ; ------- bBusy = False ENDFUNCTION ;-------------------------- FUNCTION BB_ClearSchedule() ;-------------------------- IF ( bBusy ) RETURN ; - STOP - Do not clear more than once! ENDIF ;--------------------- bBusy = TRUE ; ------- quest q int i = 0 WHILE (i < BB_ActiveSchedules.Length) q = BB_ActiveSchedules[i] IF ( q ) referenceAlias RA = q.GetAlias(0) as ReferenceAlias IF ( RA ) RA.Clear() ENDIF q = None BB_ActiveSchedules[i] = q i = i + 1 ELSE i = BB_ActiveSchedules.Length ENDIF ENDWHILE i = BB_ActiveSchedules.Find(None) IF (i == -1) RETURN ; - STOP - Array is full! ENDIF ; ---------------------- int n = i ; position of first <None> entry i = i + 1 ; get next array position (init) WHILE (i < BB_ActiveSchedules.Length) q = BB_ActiveSchedules[i] IF ( q ) BB_ActiveSchedules[n] = q ; compact array by moving entry down n = n + 1 ; increase compact counter ENDIF i = i + 1 ; get next array position (update) ENDWHILE ; ------- bBusy = False ENDFUNCTION
-
The question is
a) one baseobject "Trophy_Item" or
b) 21 different baseobjects
with 21 markers to place a single trophy?
MiscObject Property Trophy_Item Auto{This is the item created by the crafting menu which triggers these events. This is the item this script is attached to.}And are the GlobalVariables used within these two scripts only?GlobalVariable Property Global_Trophy_Placed_0x Auto{The trophy global for the trophy base to know if a trophy is already in place.} -
I would suggest next code for this script. Keep in mind the script "DLC2ReferenceAliasArrayScript" has the same bug!
DLC1ReferenceAliasArrayScript
Scriptname DLC1ReferenceAliasArrayScript extends Quest {v1.5 ReDragon 2021} ; *** jduvall -- please talk to me before changing this script ; IMPORTANT! This needs to be an array of empty values with the same number of values as aliases in AliasArray. ReferenceAlias[] PROPERTY AliasArray auto ; All the aliases that make up the "array" ObjectReference[] PROPERTY RefArray auto ; "We are using a seperate array to hold references and shuffling refs around in that because it's much less ; overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin" (Bethesda) Bool threadLock ; -- FUNCTIONs -- 3 + 1 + 2 Bool PROPERTY TraceAliasRefs auto ; [Default=False] for debugging ; if TRUE, will debug.trace() all the aliases in the array after 'ForceRefInto()' or 'ClearRefFrom()' ;------------------------ FUNCTION TraceArrayRefs() ; for debugging only ;------------------------ ;int i = 0 ; WHILE (i < AliasArray.Length) ;;; Debug.Trace("Alias: "+AliasArray[i]+" has "+AliasArray[i].GetReference()) ; i = i + 1 ; ENDWHILE ENDFUNCTION ;FUNCTION LockThread() ; UnUSED by now ;ENDFUNCTION ;---------------------- FUNCTION UnlockThread() ;---------------------- threadLock = False ENDFUNCTION ;---------------------------------------------------- ReferenceAlias FUNCTION FindRef(ObjectReference oRef) ; oRef = RefToFind ;---------------------------------------------------- int i = 0 ; i = index, search now from bottom to top WHILE (i < AliasArray.Length) referenceAlias RA = AliasArray[i] ; RA = AliasToReturn IF ( RA ) IF (oRef == RA.GetReference()) RETURN RA ; objRef was found (could be an unassigned alias, if oRef == None) ENDIF ENDIF i = i + 1 ENDWHILE ;; Debug.Trace(self+" FindRef() - Could not found " +oRef+ ".. RETURN <None>") RETURN None ENDFUNCTION ;################ ;### ClearRef ######################################################################################## ;################ ;----------------------------------------------- Bool FUNCTION ClearRefFrom(ObjectReference oRef) ; oRef = RefToClear ;----------------------------------------------- WHILE (threadLock) Utility.Wait(1.0) ENDWHILE threadLock = TRUE ; *T* ;======================= referenceAlias RA = FindRef(oRef) ; RA = FoundAlias IF ( RA ) RA.Clear() ; unassigned objRef from Alias ELSE ;; Debug.Trace(self+" ClearRefFrom() - Did not find " +oRef+ " in any aliases.. RETURN False.") threadLock = False ; *** Return False ENDIF ;--------- int i = RefArray.Find(oRef) ; find position RefArray[i] = None ; and clear the entry right now ;;; RefArray[RefArray.Find(RefToClear)] = None ; Buggy! (ReDragon) ;;================================================== ; http://www.creationkit.com/Arrays_%28Papyrus%29 ; http://www.creationkit.com/index.php?title=Arrays_(Papyrus) ; The array Find() function cannot be used within an arrays element index brackets !!! ; ; myArray[myArray.Find(none)] = newValue ; no error on compiling, but ingame it will not work correctly and the value is not filled as expected. ; ; int i = myArray.Find(None) ; find the first blank element ; myArray[i] = newValue ; and fill it with our newValue ;;================================================== threadLock = False ; *** Return TRUE ENDFUNCTION ;################ ;### ForceRef ######################################################################################## ;################ 2 ;----------------------------------------------- Bool FUNCTION ForceRefInto(ObjectReference oRef) ; oRef = RefToAdd ;----------------------------------------------- ; called by "DLC1VampireMesmerizeScript", "DLC1VampireTurnScript" WHILE (threadLock) Utility.Wait(1.0) ENDWHILE threadLock = TRUE ; *T* ;======================= int i = RefArray.Find(oRef) ; i = foundRefIndex IF (i >= 0) ;; Debug.Trace(self+" ForceRefInto("+i+") - " +oRef+ " was already found in RefArray.. RETURN False.") threadLock = False ; *** Return False ENDIF ;--------- objectReference lastRef = PromoteRefs() ; lastRef = RefToReplace referenceAlias RA = FindRef(lastRef) ; RA = AliasToReplace lastRef = None IF ( RA ) ;; Debug.Trace(self + "ForceRefInto([" +oRef+ "]) will force reference into " +RA+ " which is also returned") RefArray[0] = oRef RA.ForceRefTo(oRef) ENDIF threadLock = False ; *** RETURN (RA as Bool) ; returns TRUE or False, depends on valid RefAlias ENDFUNCTION ;------------------------------------- ObjectReference FUNCTION PromoteRefs() ; internal only ;------------------------------------- objectReference lastRef ; lastRef = RefToReturn objectReference oRef ; oRef = currentRef int i = RefArray.Length - 1 ; i = index IF (i >= 0) lastRef = RefArray[i] ENDIF WHILE (i > 0) ; Do not allow a negative value here !!! oRef = RefArray[i - 1] IF ( oRef ) RefArray[i] = oRef ENDIF i = i - 1 ENDWHILE RETURN lastRef ENDFUNCTION
-
Unfortuantely papyrus script language is not always very easy to understand. Very often is an 'improvement' of vanilla scripts, a step forward to get runtime errors with improved version.
But here we have a papyrus compiler bug. https://web.archive.org/web/20200216210550/http://forums.bethsoft.com/topic/1610844-ckse-persisting-script-engine-bugs/
THHIS BUG WAS NEVER SOLVED by any release of UNOFFICIAL PATCHES!Inci wrote (2016-Nov-01):
"The compiler for SSE is still unable to properly manage temporary variables, when it compiles a nested function call inside an array index evaluation. Such a statement is compiled in a way, which causes temporary variable corruption during execution. This is the issue of 'myArray[myArray.Find(none)] = newValue' not working properly (although the same issue would actually affect a larger range of possible cases). Unfortunately, as the forum search functionality is still unavailable, I am unable to find and link to the thread, where this was originally discussed."DLC1ReferenceAliasArrayScript (vanilla code)
Scriptname DLC1ReferenceAliasArrayScript extends Quest ;jduvall -- please talk to me before changing this script ReferenceAlias[] Property AliasArray auto {All the arrays that make up the "array"} objectReference[] Property RefArray auto ;we are using a seperate array to hold references and shuffling refs around in that because its much less overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin {IMPORTANT! This needs to be an array of empty values with the same number of values as the number of aliases in AliasArray.} bool Property TraceAliasRefs auto {Debug: default = false, if true will debug.trace() contents of all the aliases in the array after ForceRefInto() or ClearRefFrom()} bool threadLock Function LockThread() while threadLock utility.wait(1) endWhile threadLock = true EndFunction Function UnlockThread() threadLock = false EndFunction bool Function ForceRefInto(objectReference RefToAdd) LockThread() bool ReturnBool int foundRefIndex = RefArray.find(RefToAdd) if foundRefIndex >= 0 Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) is already in alias [" + AliasArray[foundRefIndex] + "], so NOT forcing into anything and will RETURN FALSE.") returnBool = false else objectReference RefToReplace = PromoteRefs() ReferenceAlias AliasToReplace = FindRef(RefToReplace) Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) will and force reference into " + AliasToReplace) RefArray[0] = RefToAdd AliasToReplace.ForceRefTo(RefToAdd) returnBool = true endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction bool Function ClearRefFrom(objectReference RefToClear) LockThread() bool ReturnBool ReferenceAlias FoundAlias = FindRef(RefToClear) if FoundAlias Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) found Reference in Alias [" + FoundAlias + "], so will clear alias and RETURN TRUE") FoundAlias.Clear() RefArray[RefArray.Find(RefToClear)] = None ; !!! PAPYRUS !!! returnBool = true else Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) did NOT find reference in any aliases, will NOT clear anything, and will RETURN FALSE") returnBool = false endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction ReferenceAlias Function FindRef(objectReference RefToFind) debug.Trace(self + "FindRef([" + RefToFind + "])") int index = 0 bool found = false ReferenceAlias AliasToReturn while (index < AliasArray.Length) && found == false if AliasArray[index].GetReference() == RefToFind AliasToReturn = AliasArray[index] found = true endif index += 1 endWhile Debug.Trace(self + "FindRef([" + RefToFind + "]) found in alias " + AliasToReturn) RETURN AliasToReturn EndFunction objectReference Function PromoteRefs() Debug.Trace(self + "PromoteRefs()") int index = RefArray.Length - 1 objectReference RefToReturn = RefArray[index] while (index > 0) objectReference currentRef = RefArray[index - 1] if currentRef RefArray[index] = (currentRef) endif index -= 1 endWhile return RefToReturn EndFunction function TraceArrayRefs() int index = 0 while (index < AliasArray.Length) debug.trace("Alias: " + AliasArray[Index] + " has reference: " + AliasArray[Index].GetReference()) index += 1 endWhile EndFunction
DLC1ReferenceAliasArrayScript (Usleep version)
Scriptname DLC1ReferenceAliasArrayScript extends Quest ;jduvall -- please talk to me before changing this script ReferenceAlias[] Property AliasArray auto {All the arrays that make up the "array"} objectReference[] Property RefArray auto ;we are using a seperate array to hold references and shuffling refs around in that because its much less overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin {IMPORTANT! This needs to be an array of empty values with the same number of values as the number of aliases in AliasArray.} bool Property TraceAliasRefs auto {Debug: default = false, if true will debug.trace() contents of all the aliases in the array after ForceRefInto() or ClearRefFrom()} bool threadLock Function LockThread() while threadLock utility.wait(1) endWhile threadLock = true EndFunction Function UnlockThread() threadLock = false EndFunction bool Function ForceRefInto(objectReference RefToAdd) LockThread() bool ReturnBool int foundRefIndex = RefArray.find(RefToAdd) if foundRefIndex >= 0 ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) is already in alias [" + AliasArray[foundRefIndex] + "], so NOT forcing into anything and will RETURN FALSE.") returnBool = false else objectReference RefToReplace = PromoteRefs() ReferenceAlias AliasToReplace = FindRef(RefToReplace) ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) will and force reference into " + AliasToReplace) RefArray[0] = RefToAdd AliasToReplace.ForceRefTo(RefToAdd) returnBool = true endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction bool Function ClearRefFrom(objectReference RefToClear) LockThread() bool ReturnBool ReferenceAlias FoundAlias = FindRef(RefToClear) if FoundAlias ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) found Reference in Alias [" + FoundAlias + "], so will clear alias and RETURN TRUE") FoundAlias.Clear() RefArray[RefArray.Find(RefToClear)] = None ; !!! PAPYRUS !!! returnBool = true else ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) did NOT find reference in any aliases, will NOT clear anything, and will RETURN FALSE") returnBool = false endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction ReferenceAlias Function FindRef(objectReference RefToFind) ;debug.Trace(self + "FindRef([" + RefToFind + "])") int index = 0 bool found = false ReferenceAlias AliasToReturn while (index < AliasArray.Length) && found == false if AliasArray[index].GetReference() == RefToFind AliasToReturn = AliasArray[index] found = true endif index += 1 endWhile ;Debug.Trace(self + "FindRef([" + RefToFind + "]) found in alias " + AliasToReturn) RETURN AliasToReturn EndFunction objectReference Function PromoteRefs() ;Debug.Trace(self + "PromoteRefs()") int index = RefArray.Length - 1 objectReference RefToReturn = RefArray[index] while (index > 0) objectReference currentRef = RefArray[index - 1] if currentRef RefArray[index] = (currentRef) endif index -= 1 endWhile return RefToReturn EndFunction function TraceArrayRefs() int index = 0 while (index < AliasArray.Length) ;debug.trace("Alias: " + AliasArray[Index] + " has reference: " + AliasArray[Index].GetReference()) index += 1 endWhile EndFunction
DLC1ReferenceAliasArrayScript (subhuman version)
Scriptname DLC1ReferenceAliasArrayScript extends Quest ;jduvall -- please talk to me before changing this script ReferenceAlias[] Property AliasArray auto {All the arrays that make up the "array"} objectReference[] Property RefArray auto ;we are using a seperate array to hold references and shuffling refs around in that because its much less overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin {IMPORTANT! This needs to be an array of empty values with the same number of values as the number of aliases in AliasArray.} bool Property TraceAliasRefs auto {Debug: default = false, if true will debug.trace() contents of all the aliases in the array after ForceRefInto() or ClearRefFrom()} bool threadLock Function LockThread() while threadLock ; VSmO subhuman - 1 second is far too long to wait for array accesses, when papyrus can do thousands per second ; utility.wait(1) utility.wait(0.1) endWhile threadLock = true EndFunction Function UnlockThread() threadLock = false EndFunction bool Function ForceRefInto(objectReference RefToAdd) LockThread() bool ReturnBool int foundRefIndex = RefArray.find(RefToAdd) if foundRefIndex >= 0 ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) is already in alias [" + AliasArray[foundRefIndex] + "], so NOT forcing into anything and will RETURN FALSE.") returnBool = false else objectReference RefToReplace = PromoteRefs() ReferenceAlias AliasToReplace = FindRef(RefToReplace) ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) will and force reference into " + AliasToReplace) RefArray[0] = RefToAdd AliasToReplace.ForceRefTo(RefToAdd) returnBool = true endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction bool Function ClearRefFrom(objectReference RefToClear) LockThread() bool ReturnBool ReferenceAlias FoundAlias = FindRef(RefToClear) if FoundAlias ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) found Reference in Alias [" + FoundAlias + "], so will clear alias and RETURN TRUE") FoundAlias.Clear() RefArray[RefArray.Find(RefToClear)] = None returnBool = true else ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) did NOT find reference in any aliases, will NOT clear anything, and will RETURN FALSE") returnBool = false endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction ReferenceAlias Function FindRef(objectReference RefToFind) ;debug.Trace(self + "FindRef([" + RefToFind + "])") ; VSmO subhuman int index = 0 while index < AliasArray.Length if AliasArray[index].GetReference() == RefToFind return AliasArray[index] endIf index += 1 endWhile return none ;/ int index = 0 bool found = false ReferenceAlias AliasToReturn while (index < AliasArray.Length) && found == false if AliasArray[index].GetReference() == RefToFind AliasToReturn = AliasArray[index] found = true endif index += 1 endWhile ;Debug.Trace(self + "FindRef([" + RefToFind + "]) found in alias " + AliasToReturn) RETURN AliasToReturn/; EndFunction objectReference Function PromoteRefs() ;Debug.Trace(self + "PromoteRefs()") int index = RefArray.Length - 1 objectReference RefToReturn = RefArray[index] while (index > 0) objectReference currentRef = RefArray[index - 1] if currentRef RefArray[index] = (currentRef) endif index -= 1 endWhile return RefToReturn EndFunction function TraceArrayRefs() ;/ int index = 0 while (index < AliasArray.Length) ;debug.trace("Alias: " + AliasArray[Index] + " has reference: " + AliasArray[Index].GetReference()) index += 1 endWhile/; EndFunction
-
https://www.creationkit.com/index.php?title=PlayAnimation_-_ObjectReference
You wrote: "I ask for help from those who understand scripts and can write a simple script, the animation on IdleMarker should play for example (1 minute), then the character accepts its standard Idle animation."
Its not as simple as you think. You have to save the actor who is doing the animation related to IdleMarker. Now the script has to wait for each actor 60 seconds and then a stop animation has to be called to revert the actor to normal behavior. Best way would be to create a new spell (fire and forget) with a script on magic effect.
lis8IdleMarkerMGEFScript
Scriptname lis8IdleMarkerMGEFScript extends ActiveMagicEffect ; https://forums.nexusmods.com/index.php?/topic/10943138-need-help-with-script-for-idlemarker-in-skyrim/ Idle PROPERTY IdleStop_Loose auto ; vanilla animation fill in here Actor target ; -- EVENTs -- EVENT OnEffectStart(Actor akTarget, Actor akCaster) target = akTarget myF_Action(akTarget) ENDEVENT ; -- FUNCTION -- ;---------------------------------- FUNCTION myF_Action(Actor akTarget) ;---------------------------------- int i = 60 WHILE akTarget.Is3DLoaded() IF (i == 0) ;* -- edited next code lines ;;; (akTarget as ObjectReference).PlayAnimation("IdleStop_Loose") ;* stop animation, this line is rubbish here ;;; Debug.SendAnimationEvent((akTarget as ObjectReference), "IdleStop_Loose") ;* idle variant to play for actors without a property setting akTarget.PlayIdle(IdleStop_Loose) ;* -- caused by earlier brain misfunction RETURN ; - STOP - ENDIF ; --------------------- i = i - 1 ; counter Utility.Wait(1.0) ENDWHILE target = None ; remove actors script persistence ENDFUNCTION
What is the problem? I do not know how to cast the spell on the actor. You do not tell us with your post, what have you done to make the actor to interact with the idlemarker.In the same interaction you should cast the spell on the actor.
-
You wrote: "I want to create a script based magic effect, and then be able to access that script effect so I can call functions from it."
Depends on:
1. count of actors be involved by this kind of magic effect
2. content of function code to run here
there are various ways to come along with.
A simple way would be the use of a GlobalVariable with different values, which makes the magic effect to do somethings depends on value.
A script of type activemagiceffect do not have "really" a self on it! So there is no way to call functions here from other scripts like external function call, as well as property get or set.
But you can use OnUpdate() to wait for and respond of the value from a GlobalVariable. In other scripts you set the value to force action in the base magic effect.
zorakConstantMGEFScript
Scriptname zorakConstantMGEFScript extends ActiveMagicEffect ; https://forums.nexusmods.com/index.php?/topic/10939083-getting-a-reference-for-an-active-magic-effect-on-an-actor/ GlobalVariable PROPERTY myGlobal auto ; new created by CK Actor target ; -- EVENTs -- 4 EVENT OnUpdate() myF_Action() ENDEVENT EVENT OnEffectStart(Actor akTarget, Actor akCaster) target = akTarget RegisterForSingleUpdate(1.0) ENDEVENT EVENT OnEffectFinish(Actor akTarget, Actor akCaster) target = None ENDEVENT EVENT OnDying(Actor akKiller) UnRegisterForUpdate() myGlobal.SetValue(-1.0) self.Dispel() ENDEVENT ; -- FUNCTIONs -- ;-------------------- FUNCTION myF_Action() ;-------------------- IF ( target ) ELSE self.Dispel() RETURN ; - STOP - target not found! ENDIF ;--------------------- IF target.IsDead() RETURN ; - STOP - safety net.. ENDIF ;--------------------- float f = 1.0 ; 1.0 - default cooldown time int i = myGlobalGetValueInt() IF ( i ) ; (i != 0) IF (i == 1) myF_A01() ELSEIF (i == 2) myF_A02() f = 2.0 ; 2.0 update default cooldown (as a sample here) ELSEIF (i == 3) myF_A03() ENDIF ENDIF IF (i >= 0) RegisterForSingleUpdate(f) ; wait a bit before next action will be called ENDIF ENDFUNCTION ;----------------- FUNCTION myF_A01() ;----------------- ; code here ENDFUNCTION ;----------------- FUNCTION myF_A02() ;----------------- ; code here ENDFUNCTION ;----------------- FUNCTION myF_A03() ;----------------- ; code here ENDFUNCTION
-
mod: "Lawbringer" v1.3.0.2 by EpicCrab https://www.nexusmods.com/skyrimspecialedition/mods/29882
MLQ_LCOQuestScript
Scriptname MLQ_LCOQuestScript extends Quest Keyword Property CurrentOwnership Auto Keyword Property DefaultOwnership Auto ReferenceAlias[] Property ControlMarkerAliases Auto FormList Property RadiantExclusionFormList Auto Event onStoryScript(Keyword akKeyword, Location akLocation, ObjectReference akRef1, ObjectReference akRef2, int newController, int excludeFromRadiant) bool isSetupProperly = akLocation.hasKeyword(CurrentOwnership) if(newController == 0 && akLocation.hasKeyword(DefaultOwnership)) ;defaulting ownership and a specific faction is the default newController = akLocation.getKeywordData(DefaultOwnership) as int endIf if(isSetupProperly) int index = akLocation.getKeywordData(CurrentOwnership) as int ObjectReference currentControllerRef = ControlMarkerAliases[index].getReference() ObjectReference newControllerRef = ControlMarkerAliases[newController].getReference() if(currentControllerRef && !currentControllerRef.isDisabled() && newControllerRef && newControllerRef.isDisabled()) ;if any of these conditions aren't met it's best to just not deal with this currentControllerRef.disable() newControllerRef.enable() akLocation.setKeywordData(CurrentOwnership, newController as float) if(excludeFromRadiant == 0 && RadiantExclusionFormList.hasForm(akLocation)) RadiantExclusionFormList.removeAddedForm(akLocation) elseif(excludeFromRadiant != 0 && !RadiantExclusionFormList.hasForm(akLocation)) RadiantExclusionFormList.addForm(akLocation) endIf endIf else ; f*** you this is going to be so much messier now int index = ControlMarkerAliases.length ObjectReference currentControllerRef = None while (index > 0 && !currentControllerRef) index -= 1 ObjectReference temp = ControlMarkerAliases[index].getReference() if(temp && !temp.isDisabled()) currentControllerRef = temp ObjectReference newControllerRef = ControlMarkerAliases[newController].getReference() if(currentControllerRef && !currentControllerRef.isDisabled() && newControllerRef && newControllerRef.isDisabled()) currentControllerRef.disable() newControllerRef.enable() if(excludeFromRadiant == 0 && RadiantExclusionFormList.hasForm(akLocation)) RadiantExclusionFormList.removeAddedForm(akLocation) elseif(excludeFromRadiant != 0 && !RadiantExclusionFormList.hasForm(akLocation)) RadiantExclusionFormList.addForm(akLocation) endIf endIf endIf endWhile endIf stop() endEvent int function getControllerIndex(String controllerName) global ; ... code here ... endFunction
Without a specific error line its impossible to say what kind of code is throwing the errors. So I have the script partly rewritten.
If you want to compile next source keep in mind I do not added the single function from original script. Maybe the mod needs this function getControllerIndex() to work properly.
MLQ_LCOQuestScript
Scriptname MLQ_LCOQuestScript extends Quest {adjusted by ReDragon 2022-01-01} ; https://forums.nexusmods.com/index.php?/topic/10898648-papyrus-log-has-infinitely-repeating-error-that-i-cant-find-from-base-game-or-from-a-mod/ Keyword PROPERTY DefaultOwnership auto Keyword PROPERTY CurrentOwnership auto FormList PROPERTY RadiantExclusionFormList auto ; radiant exclude list ReferenceAlias[] PROPERTY ControlMarkerAliases auto ; pre-filled array of marker aliases Bool bBusy ; [default=False] ; -- EVENT -- EVENT OnStoryScript(Keyword akKeyword, Location akLocation, ObjectReference akRef1, ObjectReference akRef2, Int aiValue1, Int aiValue2) ;==================================== ; https://www.creationkit.com/index.php?title=OnStoryScript_-_Quest ; aiValue1 = newController ; aiValue2 = excludeFromRadiant IF ( bBusy ) RETURN ; - STOP - Do not allow multiple event calls to stop this quest! ENDIF ;--------------------- bBusy = TRUE ; *T* myF_Action(akLocation, aiValue1, aiValue2, akLocation.HasKeyword(CurrentOwnership)) ;;; bBusy = False ; *** self.Stop() ; stop this quest ENDEVENT ; -- FUNCTIONs -- 3 ;---------------------------------------------------- FUNCTION myF_Debug(Int n, Location akLocation, Int i) ; helper to shrink stack size ;---------------------------------------------------- IF (n == 0) Debug.Trace(self+" OnStoryScript("+i+") - ERROR-0: Location is <None> .. " +akLocation) RETURN ; - STOP - ENDIF ;--------------------- IF (n == 1) Debug.Trace(self+" OnStoryScript("+i+") - ERROR-1: Location = " +akLocation+ " has invalid KeywordData!") RETURN ; - STOP - ENDIF ;--------------------- IF (n == 2) Debug.Trace(self+" OnStoryScript("+i+") - ERROR-2: Location = " +akLocation+ " detected invalid newController value!") RETURN ; - STOP - ENDIF ;--------------------- IF (n == 3) Debug.Trace(self+" OnStoryScript("+i+") - ERROR-3: Location = " +akLocation+ " detected invalid newController value!") ENDIF ENDFUNCTION ;----------------------------------------------------- FUNCTION myF_AddRem(Location akLocation, Int aiValue2) ; internal helper ;----------------------------------------------------- IF ( akLocation ) ELSE RETURN ; - STOP - safety net ENDIF ;--------------------- int i = RadiantExclusionFormList.Find( akLocation ) IF ( aiValue2 ) ; (excludeFromRadiant != 0) IF (i < 0) RadiantExclusionFormList.AddForm(akLocation) ENDIF ELSE IF (i >= 0) RadiantExclusionFormList.RemoveAddedForm(akLocation) ENDIF ENDIF ENDFUNCTION ;----------------------------------------------------------------------------- FUNCTION myF_Action(Location akLocation, Int aiValue1, Int aiValue2, Bool bOK) ; code outsourced from event ;----------------------------------------------------------------------------- IF ( akLocation ) ELSE myF_Debug(0, akLocation, aiValue1) ; //DEBUG-0 RETURN ; - STOP - /1 ENDIF ;--------------------- IF (aiValue1 == 0) && akLocation.HasKeyword(DefaultOwnership) ; default ownership and specific faction is default aiValue1 = akLocation.GetKeywordData(DefaultOwnership) as Int ENDIF objectReference currentControllerRef objectReference newRef ; newRef = newControllerRef int i ; i = index ;--------------------- IF ( bOK ) ; bOK = isSetupProperly i = akLocation.GetKeywordData(CurrentOwnership) as Int IF (i < ControlMarkerAliases.Length) currentControllerRef = ControlMarkerAliases[i].GetReference() ; - CURRENT - ELSE myF_Debug(1, akLocation, i) ; //DEBUG-1 ENDIF ; ------------------------------------------- IF (aiValue1 < ControlMarkerAliases.Length) newRef = ControlMarkerAliases[aiValue1].GetReference() ; - NEW - ELSE myF_Debug(2, akLocation, aiValue1) ; //DEBUG-2 ENDIF ; if any of these conditions aren't met it's best to just not deal with this IF (currentControllerRef) && !currentControllerRef.IsDisabled() ELSE RETURN ; - STOP - invalid REF /or/ controller is disabled ENDIF ; ---------------------- IF (newRef) && newRef.IsDisabled() currentControllerRef.Disable() newRef.Enable() akLocation.SetKeywordData(CurrentOwnership, aiValue1 as Float) myF_AddRem(akLocation, aiValue2) ENDIF RETURN ; - STOP - isSetupProperly == TRUE ENDIF ;--------------------- ; f*** you this is going to be so much messier now i = ControlMarkerAliases.Length WHILE (i > 0) i = i - 1 currentControllerRef = ControlMarkerAliases[i].GetReference() ; temp IF (currentControllerRef) && !currentControllerRef.IsDisabled() IF (aiValue1 >= ControlMarkerAliases.Length) currentControllerRef = None myF_Debug(3, akLocation, aiValue1) ; //DEBUG-3 ELSE newRef = ControlMarkerAliases[aiValue1].GetReference() ENDIF IF (newRef) && newRef.IsDisabled() currentControllerRef.Disable() newRef.Enable() ;?; akLocation.SetKeywordData(CurrentOwnership, aiValue1 as Float) ; code line not found in original script !!! myF_AddRem(akLocation, aiValue2) RETURN ; - STOP - ENDIF ; --------------------- currentControllerRef = None newRef = None ENDIF ENDWHILE ENDFUNCTION
-
Keep in mind EquipItem() is for actors only. Your script is extending to type ObjectReference, that could be the reason why you are adding/using this: Actor Property MySelf Auto
avid_FollowerEquipScript
Scriptname avid_FollowerEquipScript extends ObjectReference ; https://forums.nexusmods.com/index.php?/topic/10902633-equipitem-does-not-equip-item/ ; baseobject of leveled items LeveledItem PROPERTY ArmorBody auto ; body LeveledItem PROPERTY ArmorHand auto ; gauntlet, gloves LeveledItem PROPERTY ArmorFeet auto ; boots ; -- EVENTs -- EVENT OnInit() gotoState("GiveItems") ; ### STATE ### RegisterForSingleUpdateGameTime(0.0) ENDEVENT EVENT OnLoad() myF_EquipMe() ; follower has 3D loaded equip the items ENDEVENT ;======================================== State GiveItems ;============== EVENT OnItemAdded(Form akBaseItem, Int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) IF (aiItemCount == 1) myF_Add(akBaseItem, akSourceContainer) ENDIF ENDEVENT EVENT OnUpdateGameTime() Utility.Wait(0.1) InitArray() ; ; *************************************************** ; We assume this script runs on the follower himself! ; *************************************************** self.AddItem(ArmorBody, 1, TRUE) Debug.Trace(self+" Body = " +ArmorBody) ; debug self.AddItem(ArmorHand, 1, TRUE) Debug.Trace(self+" gloves = " +ArmorHand) ; debug self.AddItem(ArmorFeet, 1, TRUE) Debug.Trace(self+" boots = " +ArmorFeet) ; debug ENDEVENT ;======= endState ; -- FUNCTIONs -- 4 Form[] PROPERTY ArmorArray auto Hidden Int itemCount ; [default=0] ;------------------- FUNCTION InitArray() ;------------------- ArmorArray = new Form[3] itemCount = 0 ; reset the counter as well ENDFUNCTION ;---------------------- FUNCTION DestroyArray() ;---------------------- form[] b ArmorArray = b ENDFUNCTION ;------------------------------------------------------------------- FUNCTION myF_Add(Form akBaseItem, ObjectReference akSourceContainer) ;------------------------------------------------------------------- IF ( akSourceContainer ) RETURN ; - STOP - item was given by actor (player as well) /or/ taken from container ENDIF ;--------------------- itemCount += 1 ; increase by 1 IF (itemCount == 1) ArmorArray[0] = akBaseItem RETURN ; - STOP - ENDIF ;--------------------- IF (itemCount == 2) ArmorArray[1] = akBaseItem RETURN ; - STOP - ENDIF ;--------------------- IF (itemCount == 3) gotoState("") ; ### STATE ### got all three items ArmorArray[2] = akBaseItem IF self.Is3DLoaded() myF_EquipMe() ENDIF ENDIF ENDFUNCTION ;--------------------- FUNCTION myF_EquipMe() ;--------------------- actor aRef = (self as ObjectReference) as Actor ; EquipItem() is exclusive for Actors and needs 3D loaded IF (ArmorArray.Length == 3) aRef.EquipItem( ArmorArray[0] ) aRef.EquipItem( ArmorArray[1] ) aRef.EquipItem( ArmorArray[2] ) ENDIF ENDFUNCTION
-
You wrote: "any thoughts would be welcome"
I think you should split your function in subfunctions to get a better overview. In my opinion the "Adventurer_Array" is wrong initialized!
maybe next code is useful to you
; https://forums.nexusmods.com/index.php?/topic/10894493-form-list-comparison-question/ Faction PROPERTY PotentialFollowerFaction auto Faction PROPERTY DTPotentialFollower auto FormList PROPERTY DTFollowersToExcludeList auto Int PROPERTY NPC_Form_Type auto ; set to 0x?? ;------------------------------ FUNCTION Get_Adventurer_Array() ;------------------------------ int[] b = new Int[1] ; b = Base_Form_Types b[0] = NPC_Form_Type objectReference[] a = SkyPal_References.All() ;* a = NPC_Array Debug.MessageBox("NPCs found " +a.Length) a = SkyPal_References.Filter_Form_Types(NPC_Array, b) ;* limit array to NPC_Form_Type Debug.MessageBox("Characters found " + a.Length) myF_DestroyArray() ;;; Adventurer_Array = new Actor[128] ; !!! int i = 0 ; i = Index WHILE (i < a.Length) actor aRef = a[i] as Actor ; aRef = ref_to_check IF ( aRef ) IF aRef.IsInFaction(DTPotentialFollower) ; already in this faction ELSEIF DTFollowersToExcludeList.HasForm(aRef as Form) ; *** suggested by Ghaunadaur *** ; actor found in exclude list ;?; ELSEIF DTFollowersToExcludeList.HasForm( aRef.GetBaseObject() ) ; depends on: What is the content of your formlist?, this could also work ; actorbase found ELSEIF aRef.IsInFaction(PotentialFollowerFaction) myF_ADD(aRef, Utility.RandomInt(0, 100)) ENDIF ENDIF i = i + 1 ENDWHILE Debug.MessageBox("Adventurers found " +Adventurer_Array.Length) ENDFUNCTION Actor[] PROPERTY Adventurer_Array auto Hidden ; property here to get access from other scripts ;-------------------------- FUNCTION myF_DestroyArray() ;-------------------------- actor[] b Adventurer_Array = b ENDFUNCTION ;----------------------- FUNCTION myF_InitArray() ;----------------------- Adventurer_Array = new Actor[128] ENDFUNCTION ;---------------------------------- FUNCTION myF_ADD(Actor aRef, Int r) ;---------------------------------- ArrayAddRef(Adventurer_Array, aRef) ;** no idea what function is that?? aRef.RemoveFromFaction(PotentialFollowerFaction) aRef.AddToFaction(DTPotentialFollower) aRef.SetRelationshipRank(Game.GetPlayer(), 0) aRef.SetFactionRank(DTPotentialFollower, r) ; valid range: -128 .. 127 ENDFUNCTION
-
You wrote: "I am trying to make a lesser power"
This kind of scripting is called cheating. Nothing more to write.
Populating MCM AddMenuOptionST with player spells and lesser powers
in Creation Kit and Modders
Posted · Edited by ReDragon2013
I finally go through the papyrus source code and I was really astonished about this construct
(1) Next code line makes no sense, should be removed!
(2) We know its not possible to have a duplicated spell by creation process, so we take the default value
version 10 with threading
For race specific spells, you have to create a formlist which has the vanilla spells. If DLCs or other mods should have such spells you can look for mod loaded by GeFormFromFile() and add such spell to list on the fly by using this https://www.creationkit.com/index.php?title=AddForm_-_FormList
Sometimes it makes a different in runtime to use Utility.Wait() in functions and/or events.
(3) maybe its faster to use this SKSE native spell function instead to get the MagicEffect of spell and check for ME.castingtype()