Jump to content

Partial solution: Take All Unequipped


ThoraldGM

Recommended Posts

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

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 by Reneer
Link to comment
Share on other sites

 

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

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 by Reneer
Link to comment
Share on other sites

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

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 by PoliteRaider
Link to comment
Share on other sites

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 by Reneer
Link to comment
Share on other sites

 

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

  • Recently Browsing   0 members

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