avidichard Posted January 2, 2022 Share Posted January 2, 2022 SOLVED! - Results of the help I received here is my new follower mod: Dove - The Free Bird Initial code of initial problem in spoiler below. Scriptname MyFollowerEquip extends ObjectReference Actor Property MySelf Auto LeveledItem Property MyArmorBody Auto LeveledItem Property MyArmorHand Auto LeveledItem Property MyArmorFeet Auto Form Property MyFollowerArmor1 Auto Form Property MyFollowerArmor2 Auto Form Property MyFollowerArmor3 Auto Int itemCount = 0 Int equipItem = 0 Bool bEquip = false Bool bDebugOut = true ; ======================================== ; On Script initialise ; ======================================== Event OnInit() Debug.Trace ("==============================") Debug.Trace ("MyFollower - INITIALIZED") Debug.Trace ("==============================") ; Add the body armor MySelf.AddItem(MyArmorBody,1,true) Debug.Trace ("==============================") Debug.Trace ("MyFollower - Add BODY") Debug.Trace ("==============================") MySelf.AddItem(MyArmorHand,1,true) Debug.Trace ("==============================") Debug.Trace ("MyFollower - Add GLOVES") Debug.Trace ("==============================") MySelf.AddItem(MyArmorFeet,1,true) Debug.Trace ("==============================") Debug.Trace ("MyFollower - Add BOOTS") Debug.Trace ("==============================") ; Call the update routine to check added items and equip them MyFollowerUpdate() EndEvent ; ======================================== ; On Item Add ; ======================================== Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) Debug.Trace ("==============================") Debug.Trace ("MyFollower - TREATING AddedItem "+akBaseItem+" ("+aiItemCount+"x)") Debug.Trace ("==============================") ; ========== ; Set the added item ; ========== if (!akSourceContainer == Game.GetPlayer()) ; Add 1 to item count itemCount = itemCount + 1 ; ========== ; Set new form references ; ========== if (itemCount == 1) MyFollowerArmor1 = akBaseItem Debug.Trace ("==============================") Debug.Trace ("MyFollower - Armor1 SET to "+MyFollowerArmor1) Debug.Trace ("==============================") endIf if (itemCount == 2) MyFollowerArmor2 = akBaseItem Debug.Trace ("==============================") Debug.Trace ("MyFollower - Armor2 SET to "+MyFollowerArmor2) Debug.Trace ("==============================") endIf if (itemCount == 3) MyFollowerArmor3 = akBaseItem bEquip = true Debug.Trace ("==============================") Debug.Trace ("MyFollower - Armor3 SET to "+MyFollowerArmor3) Debug.Trace ("==============================") endIf endIf endEvent ; ======================================== ; Enable OnUpdate ; ======================================== Function MyFollowerUpdate() Debug.Trace ("==============================") Debug.Trace ("MyFollower - Event: OnUpdate REGISTERED") Debug.Trace ("==============================") RegisterForUpdate(1.0) EndFunction ; ======================================== ; Check periodically until we have all 3 armor pieces ; ======================================== Event OnUpdate() Debug.Trace ("==============================") Debug.Trace ("MyFollower - Event: OnUpdate TRIGGERED -- bEquip="+bEquip) Debug.Trace ("==============================") if (bEquip) UnregisterForUpdate() bEquip = false equipItem = equipItem + 1 MySelf.EquipItem(MyFollowerArmor1) Debug.Trace ("==============================") Debug.Trace ("MyFollower - EQUIPED Armor1 (equipItem="+equipItem+")") Debug.Trace ("==============================") equipItem = equipItem + 1 MySelf.EquipItem(MyFollowerArmor2) Debug.Trace ("==============================") Debug.Trace ("MyFollower - EQUIPED Armor2 (equipItem="+equipItem+")") Debug.Trace ("==============================") equipItem = equipItem + 1 MySelf.EquipItem(MyFollowerArmor3) Debug.Trace ("==============================") Debug.Trace ("MyFollower - EQUIPED Armor3 (equipItem="+equipItem+")") Debug.Trace ("==============================") endIf EndEvent So. 3 days without a single successful integration. I placed my Character in HelgenKeep01 and loaded a VANILLA save from there. One the game loads, my follower has her clothes on. I have another save where my folower's mod is NOT loaded but I'm outside in Riverwood. If I console "coc HelegenKeep01" and reach out to my follower, She's naked. If I console "Player.PlaceAtMe <FollowerID>" same thing, she's naked. BUT, when I go inside my Papyrus log, I get all of my "EQUIPED Armor" logs. The items are in the follower's inventory but she just does not wear them even if the code says she got her parts equiped. I only see the equiped items if I load from the saved Vanilla game directly in HelgenKeep01. So, can someone tell me what the heck is happenning and what am I doing wrong?? And NOOOOO - No outfits. It's the whole point of this code, NO OUTFITS!!!! Link to comment Share on other sites More sharing options...
ReDragon2013 Posted January 2, 2022 Share Posted January 2, 2022 (edited) 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 Edited January 2, 2022 by ReDragon2013 Link to comment Share on other sites More sharing options...
IsharaMeradin Posted January 2, 2022 Share Posted January 2, 2022 @ReDragon2013The script being extended should not matter, the OP is using an Actor property with the EquipItem function. *****************************@avidichard Since your save is in Riverwood, just run back to Helgen and enter the keep. See if the follower is wearing the clothes when the cell is loaded with a normal transition. Using COC may be preventing some things from processing properly. If you do want to COC somewhere to test your follower, go to a nearby exterior location rather than the cell where the NPC is located. Try HelgenExterior instead of HelgenKeep01. Is your follower intended to be in Helgen keep in the finished product? If yes, you should be aware of a few things: For those not using an alternate start mod, their hands will not be unbound until after entering the keep. OnUpdateGameTime in ReDragon's example will fail to run. For some reason the game will not process GameTime related events until after the hands are unbound.For those who have already completed the Helgen tutorial and spoken with the Jarl in Whiterun, there will be bandits spawned inside. This may be problematic, especially if the follower is not protected / essential. Link to comment Share on other sites More sharing options...
avidichard Posted January 2, 2022 Author Share Posted January 2, 2022 @ReDragon2013The script being extended should not matter, the OP is using an Actor property with the EquipItem function. *****************************@avidichard Since your save is in Riverwood, just run back to Helgen and enter the keep. See if the follower is wearing the clothes when the cell is loaded with a normal transition. Using COC may be preventing some things from processing properly. If you do want to COC somewhere to test your follower, go to a nearby exterior location rather than the cell where the NPC is located. Try HelgenExterior instead of HelgenKeep01. Is your follower intended to be in Helgen keep in the finished product? If yes, you should be aware of a few things: For those not using an alternate start mod, their hands will not be unbound until after entering the keep. OnUpdateGameTime in ReDragon's example will fail to run. For some reason the game will not process GameTime related events until after the hands are unbound.For those who have already completed the Helgen tutorial and spoken with the Jarl in Whiterun, there will be bandits spawned inside. This may be problematic, especially if the follower is not protected / essential. I've been struggling all day. I saw the problem actually AND NO, my actor is not ending up in Helgen Keep. it was just a try. I placed her somewhere else in Riverwood for tests too. I have not found her definitive home yet So, here's what I found and was a bit stupid to not understand it the first time. "OnInit" only runs once on first initial load of the Character in the GAME not in the room or cell, it runs once in the entire game and will not run afterwards. If you save with that mod loaded, the OnInit Script will not run anymore since it ran already. I may have missed a few exceptions but after running and stopping the game over 50 times today, that's what happened. To make the character wear her armor, I need to also run the EquipItem OnCellLoad. Now! I wanted to test so the console "PlaceAtMe" was SUPPOSED to be usefull to prevent travelling. So basically, when travelling with my new script edits, the character dresses up without a hitch. The problem I have though is when I PlaceAtMe, my character returns back to naked as soon as I exit console and see my second character appear. So THAT was a surprise for me because I thought that PlaceAtMe simple moved the follower from it's original location to where I am, not create a double. So, I am trying to keep her dressed even when someone triggers a PlaceAtMe command. The weird thing is, the OnInit script runs AGAIN with 0'd values but once I add Items in her inventory, the items are added in my first character's inventory and strips everyone naked. My second character appears with no items in her inventory. Another thing to note is that OnInit has 0's values but as soon as the OnItemAdded script runs, the values are back to when the initial character spawned in the game. I tried to use: Actor MyWorldFollower = MySelf.GetObjectBase() as Actor And then use MyWorldFollower to additems, but that does not work. Here's my new code in the spoiler: Scriptname MyFollowerEquip extends ObjectReference Actor Property MySelf Auto LeveledItem Property MyArmorBody Auto LeveledItem Property MyArmorHand Auto LeveledItem Property MyArmorFeet Auto Form Property MyFollowerArmor1 Auto Form Property MyFollowerArmor2 Auto Form Property MyFollowerArmor3 Auto Int itemCount = 0 Int equipItem = 0 Int bEquip = 0 Bool bShowDebug = true ; ======================================== ; On Script initialise ; ======================================== Event OnInit() if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - INITIALIZED") Debug.Trace ("==============================") Debug.Trace ("==============================") Debug.Trace ("MyFollower - OnInit: itemCount="+itemCount+", equipItem="+equipItem+", bEquip="+bEquip) Debug.Trace ("==============================") endIf ; Do not add items if they are already set if itemCount == 0 ; Add the body armor MySelf.AddItem(MyArmorBody,1,true) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Add BODY") Debug.Trace ("==============================") endIf MySelf.AddItem(MyArmorHand,1,true) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Add GLOVES") Debug.Trace ("==============================") endIf MySelf.AddItem(MyArmorFeet,1,true) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Add BOOTS") Debug.Trace ("==============================") endIf endIf ; Call the update routine to check added items and equip them MyFollowerUpdate() EndEvent ; ======================================== ; On Item Add ; ======================================== Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - TREATING AddedItem "+akBaseItem+" ("+aiItemCount+"x)") Debug.Trace ("==============================") endIf ; ========== ; Set the added item ; ========== if (akSourceContainer == None) ; This portion is for those funny people using PlaceAtMe ; ========== ; ========== if itemCount == 3 if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - itemCount="+itemCount+", bEquip="+bEquip+", Armor: "+MyFollowerArmor1) Debug.Trace ("==============================") endIf if akBaseItem == MyFollowerArmor1 EquipStarterArmor(1) endif if akBaseItem == MyFollowerArmor2 EquipStarterArmor(2) endif if akBaseItem == MyFollowerArmor3 EquipStarterArmor(3) endif return endIf ; ========== ; ========== ; Add 1 to item count, maximum of 3 itemCount = itemCount + 1 ; ========== ; Set new form references ; ========== if (itemCount == 1) MyFollowerArmor1 = akBaseItem if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Armor1 SET to "+MyFollowerArmor1) Debug.Trace ("==============================") endIf endIf if (itemCount == 2) MyFollowerArmor2 = akBaseItem if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Armor2 SET to "+MyFollowerArmor2) Debug.Trace ("==============================") endIf endIf if (itemCount == 3) MyFollowerArmor3 = akBaseItem bEquip = 1 if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Armor3 SET to "+MyFollowerArmor3) Debug.Trace ("==============================") endIf endIf endIf endEvent ; ======================================== ; Enable OnUpdate ; ======================================== Function MyFollowerUpdate() if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Event: OnUpdate REGISTERED") Debug.Trace ("==============================") endIf RegisterForUpdate(1.0) EndFunction ; ======================================== ; Check periodically until we have all 3 armor pieces ; ======================================== Event OnUpdate() if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Event: OnUpdate TRIGGERED (bEquip="+bEquip+")") Debug.Trace ("==============================") endIf ; Unregister Update request UnregisterForUpdate() if (bEquip == 1) && (equipItem == 0) if MySelf.IsInLocation(Game.GetPlayer().GetCurrentLocation()) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Is with player") Debug.Trace ("==============================") endIf bEquip = 2 endIf endIf ; Equip item if player is in the same location on Script initialise if (bEquip == 2) && (equipItem == 0) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - OnInit - Equip armor") Debug.Trace ("==============================") endIf EquipStarterArmor() endIf EndEvent Event OnCellLoad() if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - OnCellLoad TRIGGERED (equipItem="+equipItem+", bEquip="+bEquip+")") Debug.Trace ("==============================") endIf if (bEquip < 100 && bEquip > 0) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - OnCellLoad - Equip armor") Debug.Trace ("==============================") endIf EquipStarterArmor() endIf EndEvent Event OnLoad() if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - OnLoad TRIGGERED (equipItem="+equipItem+", bEquip="+bEquip+")") Debug.Trace ("==============================") endIf if (bEquip < 100 && bEquip > 0) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - OnLoad - Equip armor") Debug.Trace ("==============================") endIf EquipStarterArmor() endIf EndEvent ; Equip the starter armor Function EquipStarterArmor(Int iArmorNum = 0) if (bShowDebug && iArmorNum > 0) Debug.Trace ("==============================") Debug.Trace ("MyFollower - EQUIP called (iArmorNum="+iArmorNum+")") Debug.Trace ("==============================") endIf ; Item #1 if bEquip < 100 equipItem = equipItem + 1 endIF if (iArmorNum == 0 || iArmorNum == 1) MySelf.EquipItem(MyFollowerArmor1) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - EQUIPED Armor1 (equipItem="+equipItem+")") Debug.Trace ("==============================") endIf endIf ; Item #2 if bEquip < 100 equipItem = equipItem + 1 endIF if (iArmorNum == 0 || iArmorNum == 2) MySelf.EquipItem(MyFollowerArmor2) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - EQUIPED Armor2 (equipItem="+equipItem+")") Debug.Trace ("==============================") endIf endIf ; Item #3 if bEquip < 100 equipItem = equipItem + 1 endIF if (iArmorNum == 0 || iArmorNum == 3) MySelf.EquipItem(MyFollowerArmor3) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - EQUIPED Armor3 (equipItem="+equipItem+")") Debug.Trace ("==============================") endIf endIf ; Set Armor value to 100 percent equiped bEquip = 100 endFunction Link to comment Share on other sites More sharing options...
IsharaMeradin Posted January 2, 2022 Share Posted January 2, 2022 I think you need to understand some basics.PlaceAtMe spawns a new instance of the object.Each instance of an object has its own instance of any attached scripts. Taking that knowledge, look at your script. You have an Actor property that points to your actor, each instance created by PlaceAtMe will use that assigned value. Thus your original pre-placed actor will get all the added items (as you have discovered). Before using the Actor property, try adding the following: If ((Self as ObjectReference) as Actor) != mySelf) mySelf = ((Self as ObjectReference) as Actor) EndIfThis should assign the PlaceAtMe actor into the mySelf actor property. Thus allowing the script to use them instead of the original. NOTE: something similar to the above was already in ReDragon2013's posted code. Link to comment Share on other sites More sharing options...
avidichard Posted January 2, 2022 Author Share Posted January 2, 2022 I think you need to understand some basics.PlaceAtMe spawns a new instance of the object.Each instance of an object has its own instance of any attached scripts. Taking that knowledge, look at your script. You have an Actor property that points to your actor, each instance created by PlaceAtMe will use that assigned value. Thus your original pre-placed actor will get all the added items (as you have discovered). Before using the Actor property, try adding the following: If ((Self as ObjectReference) as Actor) != mySelf) mySelf = ((Self as ObjectReference) as Actor) EndIfThis should assign the PlaceAtMe actor into the mySelf actor property. Thus allowing the script to use them instead of the original. NOTE: something similar to the above was already in ReDragon2013's posted code.OMG!!! This litterally corrected all the issues. I did correct your code though, you missed to open a bracket "(" but my oh my!!! I just learned something very valuable in Skyrim Papyrus today! ; ======================================== ; On Script initialise ; ======================================== Event OnInit() If (((Self as ObjectReference) as Actor) != MySelf) MySelf = ((Self as ObjectReference) as Actor) if bShowDebug Debug.Trace ("==============================") Debug.Trace ("MyFollower - Changed MySelf to spawned Self") Debug.Trace ("==============================") EndIf EndIf There is a delay between the character spawn and when the armor gets equiped, but I accept this price to pay for anyone wishing to console cheat their way and get the character with a "PlaceAtMe" command. I also had a very hard time compiling using the CreationKit because of how extremely long it takes to show the list and then navigate through the entire list to only check my custom script so it compiles only one script. This interface could have used AT LEAST a search or filter. But I found on NexusMods a Notepad++ plugin which compiles it for you and makes the task just that much quicker. If I need serious error detection, I compile through CreationKit but once the Compilation there goes without a hitch, I compile through the Notepad++'s Papyrus plugin! This makes me so Happy today. I can finally move on to place her somewhere in Skyrim and possibly get going on learning about something else. I did not decide if I'll release her as a basic Follow Me follower or try to integrate a small quest. I never played with quests before, or, I should rather say, I never CREATED a new quest before. I want something simple that won't interfere much in the Vanilla game. I sure will not forget to thank you on my mod page. This has been of great help! The wonderful world of programming, 3 lines to solve one issue. I just have a small question. Can we have a "if" statement without an "endif" all on one line. For example: Int MyVar = 0 Bool MyBool = false ; A one line if statement If (MyVar == 1) MyBool = true else MyBool = false Link to comment Share on other sites More sharing options...
IsharaMeradin Posted January 2, 2022 Share Posted January 2, 2022 You always need to have the EndIf on a separate line. Papyrus will complain and not compile the script if you do not. You can avoid the long wait time for all the scripts to load by doing the following:Open the record holding the scriptOpen the script from there and then build / compile the script. There is another way to compile fairly quickly, I just do not remember what it is off the top of my head. Compiling with Notepad++ is perfectly acceptable too. If you understand what you are doing you can even set up multiple source directories for N++. I do something similar with Sublime Text. Other than fragments, I think I have not used the CK to compile scripts in forever. Link to comment Share on other sites More sharing options...
avidichard Posted January 3, 2022 Author Share Posted January 3, 2022 You always need to have the EndIf on a separate line. Papyrus will complain and not compile the script if you do not. You can avoid the long wait time for all the scripts to load by doing the following:Open the record holding the scriptOpen the script from there and then build / compile the script. There is another way to compile fairly quickly, I just do not remember what it is off the top of my head. Compiling with Notepad++ is perfectly acceptable too. If you understand what you are doing you can even set up multiple source directories for N++. I do something similar with Sublime Text. Other than fragments, I think I have not used the CK to compile scripts in forever.Thanks a whole lot for your help. Your answers were extremely helpful! Happy New Year to you!!!! Link to comment Share on other sites More sharing options...
Sphered Posted January 3, 2022 Share Posted January 3, 2022 Game ---> Compile Papyrus Scripts delay time is directly impacted by how many sources there are for it to scan. The CK is very inefficient here and will do this scan each and every single time. To drastically cut that down, ditch the excess source disease. TIF files. DLC, scene fragments. Ditch that crap Above said, do this in a standalone session of Sky Classic CK. Takes mine one actual second to show the list of source to choose from. Only way to do it sanely if you prefer to use the CK to compile Link to comment Share on other sites More sharing options...
Recommended Posts