PoliteRaider Posted March 18, 2016 Share Posted March 18, 2016 Plus the advantage to working with Papyrus is it means that it's a lot more customizable, you could do all sorts of interesting things much more easily when it's in papyrus. For example it could leave quest items behind or you could relate it to the value/weight, etc, etc. Did you change the SWF so that when you click the Take All button it triggers the papyrus script or does this work purely within papyrus somehow? Link to comment Share on other sites More sharing options...
ThoraldGM Posted March 18, 2016 Author Share Posted March 18, 2016 I'm excited to check this out when I get home tonight. All the better if Papyrus eliminates the need to learn more syntax. Fantastic :-) Link to comment Share on other sites More sharing options...
Reneer Posted March 18, 2016 Share Posted March 18, 2016 (edited) Plus the advantage to working with Papyrus is it means that it's a lot more customizable, you could do all sorts of interesting things much more easily when it's in papyrus. For example it could leave quest items behind or you could relate it to the value/weight, etc, etc. Did you change the SWF so that when you click the Take All button it triggers the papyrus script or does this work purely within papyrus somehow?Purely within Papyrus. No changes at all to the SWF file. I used a few tricksy Papyrus functions to call remote events and suchlike. I'm excited to check this out when I get home tonight. All the better if Papyrus eliminates the need to learn more syntax. Fantastic :-)I'll see if I can get it out later today. But for now, a nap. Edited March 18, 2016 by Reneer Link to comment Share on other sites More sharing options...
ThoraldGM Posted March 18, 2016 Author Share Posted March 18, 2016 Nice. I would love to see a dump in Pastebin or something, but I will be home tonight to check it out. I should definitely study your work on this and the radio mod to get ready for the CK mod rush. Link to comment Share on other sites More sharing options...
PoliteRaider Posted March 18, 2016 Share Posted March 18, 2016 Plus the advantage to working with Papyrus is it means that it's a lot more customizable, you could do all sorts of interesting things much more easily when it's in papyrus. For example it could leave quest items behind or you could relate it to the value/weight, etc, etc. Did you change the SWF so that when you click the Take All button it triggers the papyrus script or does this work purely within papyrus somehow?Purely within Papyrus. No changes at all to the SWF file. I'm excited to check this out when I get home tonight. All the better if Papyrus eliminates the need to learn more syntax. Fantastic :-)I'll see if I can get it out later today. But for now, a nap. Pure genius. :D I'm burning with curiosity to know how you did it but I think I need some sleep as well anyway. I still want to tinker around a bit with the .swf files since I think there's some definite future possibilities there beyond just the take all function but it's awesome that you found a way to not even need them for this. Link to comment Share on other sites More sharing options...
Reneer Posted March 18, 2016 Share Posted March 18, 2016 (edited) Oh, you guys just want to see the script? Of course! Enjoy all the silly comments. It is still a little finnicky, but I'm iterating it pretty quickly. There are a few things I need to change (mostly sanity checks). ScriptName RenContainerScript extends Quest FollowersScript companionscript Form[] companionequipped Form[] dogmeatequipped bool gavetradecommand = false int mytimer = 10 Event OnInit() companionscript = Game.GetFormFromFile(0x000289E4, "Fallout4.esm") As FollowersScript companionequipped = new Form[128] dogmeatequipped = new Form[128] ;Self.RegisterForRemoteEvent(companionscript.Companion as ScriptObject, "OnCommandModeGiveCommand") ;Self.RegisterForRemoteEvent(companionscript.Companion as ScriptObject, "OnCommandModeCompleteCommand") Self.RegisterForRemoteEvent(companionscript.Companion as ScriptObject, "OnItemEquipped") Self.RegisterForRemoteEvent(companionscript.Companion as ScriptObject, "OnItemUnequipped") ;Self.RegisterForRemoteEvent(companionscript.DogmeatCompanion as ScriptObject, "OnCommandModeGiveCommand") ;Self.RegisterForRemoteEvent(companionscript.DogmeatCompanion as ScriptObject, "OnCommandModeCompleteCommand") Self.RegisterForRemoteEvent(companionscript.DogmeatCompanion as ScriptObject, "OnItemEquipped") Self.RegisterForRemoteEvent(companionscript.DogmeatCompanion as ScriptObject, "OnItemUnequipped") ;Self.StartTimer(1, mytimer) debug.trace("Set up NPC container quest", 0) endEvent Function OnTimer(int timerid) ; this seems to break things, not sure why yet. ; not really needed, though. if (timerid == mytimer) ; check to make sure things are still equipped... int i = 0 Actor ActorRef = companionscript.Companion.GetActorReference() while (i < companionequipped.length) if (companionequipped[i] != none && ActorRef.GetItemCount(companionequipped[i]) >= 1) if (ActorRef.IsEquipped(companionequipped[i]) == false) ActorRef.EquipItem(companionequipped[i], false, true) endif endif i += i endWhile i = 0 ActorRef = companionscript.DogmeatCompanion.GetActorReference() while (i < dogmeatequipped.length) if (dogmeatequipped[i] != none && ActorRef.GetItemCount(dogmeatequipped[i]) >= 1) if (ActorRef.IsEquipped(dogmeatequipped[i]) == false) ActorRef.EquipItem(companionequipped[i], false, true) endif endif i += i endWhile endif ;Self.StartTimer(1, mytimer) EndFunction Function ::remote_ReferenceAlias_OnCommandModeGiveCommand(ReferenceAlias akSender, int aeCommandType, ObjectReference akTarget) ; no longer needed. Was never able to figure out aeCommandType debug.trace("Command: " + aeCommandType, 0) if (aeCommandType == 6) If (akSender == companionscript.Companion || akSender == companionscript.DogmeatCompanion) ; giving command to either companion or dogmeat gavetradecommand = true endif endif EndFunction Function ::remote_ReferenceAlias_OnCommandModeCompleteCommand(ReferenceAlias akSender, int aeCommandType, ObjectReference akTarget) ; no longer needed debug.trace("Command: " + aeCommandType, 0) if (aeCommandType == 6 && (akSender == companionscript.Companion || akSender == companionscript.DogmeatCompanion)) gavetradecommand = false endif EndFunction Function ::remote_ReferenceAlias_OnItemUnequipped(ReferenceAlias akSender, Form akBaseObject, ObjectReference akReference) debug.trace("OnItemUnequipped: " + akSender, 0) if (Game.GetPlayer().IsSneaking() == false) Actor ActorRef = akSender.GetActorReference() ; need to transfer item from player back to companion if (Game.GetPlayer().GetItemCount(akBaseObject) >= 1 && ActorRef.GetItemCount(akBaseObject) <= 0) Game.GetPlayer().RemoveItem(akBaseObject, 1, true, ActorRef As ObjectReference) endif if (akSender == companionscript.Companion) if (companionequipped.Find(akBaseObject) >= 0) ActorRef.EquipItem(akBaseObject, false, true) debug.trace("EquipItem: " + akBaseObject.GetFormID(), 0) endif elseif (akSender == companionscript.DogmeatCompanion) if (dogmeatequipped.Find(akBaseObject) >= 0) ActorRef.EquipItem(akBaseObject, false, true) debug.trace("EquipItem: " + akBaseObject.GetFormID(), 0) endif endif else if (akSender == companionscript.Companion) if (companionequipped.Find(akBaseObject) >= 0) ; remove from list int emptyslot = companionequipped.Find(akBaseObject) companionequipped[emptyslot] = none debug.trace("Removed " + akBaseObject.GetFormID() + " from " + emptyslot, 0) endif elseif (akSender == companionscript.DogmeatCompanion) if (dogmeatequipped.Find(akBaseObject) >= 0) ; remove from list int emptyslot = dogmeatequipped.Find(akBaseObject) dogmeatequipped[emptyslot] = none debug.trace("Removed " + akBaseObject.GetFormID() + " from " + emptyslot, 0) endif endif endif EndFunction Function ::remote_ReferenceAlias_OnItemEquipped(ReferenceAlias akSender, Form akBaseObject, ObjectReference akReference) debug.trace("OnItemEquipped: " + akSender, 0) if (akSender == companionscript.Companion) if (companionequipped.Find(akBaseObject) < 0) ; not equipped int emptyslot = companionequipped.Find(none) companionequipped[emptyslot] = akBaseObject debug.trace("Added " + akBaseObject.GetFormID() + " to " + emptyslot, 0) endif elseif (akSender == companionscript.DogmeatCompanion) if (dogmeatequipped.Find(akBaseObject) < 0) ; not equipped int emptyslot = dogmeatequipped.Find(none) dogmeatequipped[emptyslot] = akBaseObject debug.trace("Added " + akBaseObject.GetFormID() + " to " + emptyslot, 0) endif endif EndFunction Edited March 18, 2016 by Reneer Link to comment Share on other sites More sharing options...
ThoraldGM Posted March 18, 2016 Author Share Posted March 18, 2016 Thanks. There is a wealth of info here to digest. Especially interested in how to hook into the esm with that hex reference, how you knew which functions were defined for that reference, and whether there are lists of available options for both. It's like you broke through a wall I keep running into that's beyond my read access. I will be dissecting this for awhile. Thank you very, very much. Link to comment Share on other sites More sharing options...
PoliteRaider Posted March 18, 2016 Share Posted March 18, 2016 (edited) Especially interested in how to hook into the esm with that hex reference, how you knew which functions were defined for that reference, and whether there are lists of available options for both. It's like you broke through a wall I keep running into that's beyond my read access. Well I can sort of help there but only a little. If you look in FO4Edit 289e4 is the Quest: Followers "Follower & Companion System Control Quest" [QUST:000289E4] which is being opened As FollowersScript which refers to FollowersScript.pex in Data/Scripts. Again looking at FO4Edit this script is run by this quest as part of the VMAD record for Virtual Machine Adapter. The functions aren't part of the FollowersScript themselves, but if you decompile the FollowersScript with Caprica you can see that the FollowerScript registers itself for these functions as remote events on the Player. For example line 3021 of FollowersScript.pex is:CALLMETHOD RegisterForRemoteEvent self ::temp4 ::temp3 "OnCommandModeGiveCommand" ;@line 101 (Temp 3 is earlier defined by the script as a reference to the player and temp4 is just a boolean variable) and... I'm still figuring out the rest of it but... wow! I had no idea any of this was possible until I saw Reneer had done it. Thanks Reneer, it's an education seeing you doing this. Edited March 18, 2016 by PoliteRaider Link to comment Share on other sites More sharing options...
Reneer Posted March 18, 2016 Share Posted March 18, 2016 (edited) Thanks. There is a wealth of info here to digest. Especially interested in how to hook into the esm with that hex reference, how you knew which functions were defined for that reference, and whether there are lists of available options for both. It's like you broke through a wall I keep running into that's beyond my read access. I will be dissecting this for awhile. Thank you very, very much.You are most welcome. Much of what I did I accomplished by looking through the various Bethesda Papyrus source files after I decompiled the PEX files with Champollion. Especially interested in how to hook into the esm with that hex reference, how you knew which functions were defined for that reference, and whether there are lists of available options for both. It's like you broke through a wall I keep running into that's beyond my read access. Well I can sort of help there but only a little. If you look in FO4Edit 289e4 is the Quest: Followers "Follower & Companion System Control Quest" [QUST:000289E4] which is being opened As FollowersScript which refers to FollowersScript.pex in Data/Scripts. Again looking at FO4Edit this script is run by this quest as part of the VMAD record for Virtual Machine Adapter. The functions aren't part of the FollowersScript themselves, but if you decompile the FollowersScript with Caprica you can see that the FollowerScript registers itself for these functions as remote events on the Player. For example line 3021 of FollowersScript.pex is:CALLMETHOD RegisterForRemoteEvent self ::temp4 ::temp3 "OnCommandModeGiveCommand" ;@line 101 (Temp 3 is earlier defined by the script as a reference to the player and temp4 is just a boolean variable) and... I'm still figuring out the rest of it but... wow! I had no idea any of this was possible until I saw Reneer had done it. Thanks Reneer, it's an education seeing you doing this. Just so you know, PoliteRaider, you will most definitely want to give Champollion a whirl. It makes reading the PEX files so much easier because it decompiles them into the PSC (source) files with much better info. And one little detail: the FollowerScript registers those functions on the ReferenceAlias that points to the player's Companion / Dogmeat. Self.RegisterForRemoteEvent(Companion as ScriptObject, "OnCommandModeGiveCommand") Self.RegisterForRemoteEvent(DogmeatCompanion as ScriptObject, "OnCommandModeGiveCommand") Self.RegisterForRemoteEvent(DogmeatCompanion as ScriptObject, "OnCommandModeCompleteCommand") Edited March 18, 2016 by Reneer Link to comment Share on other sites More sharing options...
PoliteRaider Posted March 18, 2016 Share Posted March 18, 2016 Just so you know, PoliteRaider, you will most definitely want to give Champollion a whirl. It makes reading the PEX files so much easier because it decompiles them into the PSC (source) files with much better info. Oh thankyou, I'm downloading it now. And whoops, I didn't read the code quite right there. I thought it was pointing to the player, not the reference to the companion that's assigned to the player. Thanks. Link to comment Share on other sites More sharing options...
Recommended Posts