Jump to content

[Scripting help] Woodchopping block depletion


Recommended Posts

I'm looking for help modifying the script for the woodchopping block.

 

This is what I want it to do: after having chopped 6 pieces of firewood, the woodchopping block will deplete (= unusable for 1 month), a message will pop up "You can't chop anymore wood for now."

 

I want this to be seperate for each woodchopping block in the world. For instance, if I depleted the woodchopping block in Whiterun, I can still chop 6 pieces in Riverwood, till it's depleted.

 

This is the Vanilla script:

 

 

 

 

Scriptname ResourceFurnitureScript extends ObjectReference  Conditional
{script for furniture which the player can use to get resources}


formlist Property requiredItemList Auto  
{required for player to use - optional}

Message Property FailureMessage Auto  
{Message to say why you can't use this without RequiredWeapon}

MiscObject Property Resource Auto  
{what you get from using this furniture}

int Property ResourceCount = 1 Auto
{how many resources you get per use}

int property MaxResourcePerActivation = 6 auto
{How many times can this object be used before the player has to re-activate?}

int counter
; count up how many resources have been gathered on this go.

faction property CurrentFollowerFaction auto
{Used to handle player followers using the furniture object}

objectReference property NPCfollower auto hidden
{hidden property to track followers who used this}

Event OnLoad()
    BlockActivation(true)
endEvent

Event OnUnload()
    ; safety measure
    UnregisterForEvents(game.getplayer())
    if NPCfollower
        UnregisterForEvents(NPCfollower)
    endif
endEvent

auto STATE normal
Event OnActivate(ObjectReference akActionRef)
    gotoState("busy")
;     debug.trace(self + "OnActivate")
    if akActionRef == Game.GetPlayer()  || (akActionRef as actor).isInFaction(CurrentFollowerFaction)
;         debug.trace("akActionRef is either player or a follower")
        if (akActionRef as actor) != game.getPlayer()
;             debug.trace("It's a follower - store in NPCfollower property")
            ; if not the player, must be the follower
            NPCfollower = akActionRef
        endif
        bool allowActivation = true
        ; check if player has required item
        if requiredItemList
            if akActionRef.GetItemCount(requiredItemList) == 0
                if akActionRef == game.getPlayer()
                    ; only require the axe item for the player
                    allowActivation = false
;                     debug.trace("allowActivation = "+allowActivation)
                    FailureMessage.Show()
                endif
            endif
        endif

        if allowActivation
            RegisterForEvents(akActionRef)
;             debug.trace(self + "player/follower activation START")
            Activate(akActionRef, true)
;             debug.trace(self + "player/follower activation END")
        endif
    else
;         ;debug.trace(self + "non-follower NPC activation START")
        ; just activate it
        Activate(akActionRef, true)
;         ;debug.trace(self + "non-follower NPC activation END")
    endif
    gotoState("normal")
endEvent
endState

STATE busy
    ; do nothing
endState

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
;     debug.trace(self + ": animation event received=" + asEventName)
    if asEventName == "AddToInventory"
        akSource.AddItem(Resource, ResourceCount)
        ; increment counter by however many items we just received
;         debug.trace("Pre-add counter = "+counter)
        counter = (counter + resourceCount)
;         debug.trace("Post-add counter = "+counter)
        if counter >= MaxResourcePerActivation
            ; if we've bagged our limit, kick the player out.  Reset timer for next activation
;             debug.trace("Woodpile - player has gotten "+counter+" logs this go.  Kicking out.")
            counter = 0
            (akSource as actor).PlayIdle(IdleWoodchopExit)
            unregisterForEvents(akSource)
        endif
    elseif asEventName == "IdleFurnitureExit"
;         debug.trace("Resource Object Unregistering: "+self)
        ; reset the counter if I exit manually
        counter = 0
        UnregisterForEvents(akSource)
    endif
endEvent

bool isRegisteredForEvents = false

function RegisterForEvents(objectReference whoToRegister)
    ; centralize this
    isRegisteredForEvents = true
    RegisterForAnimationEvent(whoToRegister, "AddToInventory")
    RegisterForAnimationEvent(whoToRegister, "SoundPlay . NPCHumanWoodChop")
    RegisterForAnimationEvent(whoToRegister, "IdleFurnitureExit")
endFunction

function UnregisterForEvents(objectReference whoToUnregister)
    ; centralize this
    
    ; It is perfectly safe to unregister for events you never registered for, however
    ; this function is called as part of OnUnload, and if this object isn't persistent
    ; then it may be deleted by the time OnUnload runs, and these function calls will
    ; fail. Since RegisterForAnimationEvent persists us, we know it will be safe to
    ; call Unregister if we've previously Registered, even if called as a part of
    ; OnUnload
    if isRegisteredForEvents
        isRegisteredForEvents = false
        UnRegisterForAnimationEvent(whoToUnregister, "AddToInventory")
        UnRegisterForAnimationEvent(whoToUnregister, "IdleFurnitureExit")
    endif
endFunction

Idle Property IdleWoodchopExit  Auto

 

I don't know that much about scripting so I was wondering whether anyone could help me make the right adjustments to the script.

 

Thanks in advance

 

Kind regards

 

Sac

Link to comment
Share on other sites

Be quite simple in theory.

 

In brief:

Add 3 properties and 1 local variable to the script.

Do a quick check when activating if it's been x amount of days since last use, if not then display a message to say chopping block is depleted.

If it's been greater then x days then process the activation.

 

3 Properties and a local variable to add:

First property would be for so you can get the Game Days passed, which is a native game global variable.

So you would add to the script and fill it in CK (Auto-Fill will fill this property for you):

GlobalVariable Property GameDaysPassed Auto

Second Property to add would be a float value of How many game days you want to specify before it can be used again:

Float Property ResetDays = 30.0 Auto

I gave it a default value of 30 days, but you can a fill a value in CK to how ever many days you'd want before it resets.

 

Third property would be a Message to display when the user activates the chopping block and it's not ready to be used:

Message Property NotReadyMsg Auto

 

Lastly a local variable that we use to store a time stamp so you can check if the days passed is less or more then the require reset days:

Float LastTimeStamp

 

Now fit a small check into the script when the copping block is activated:

If (GameDaysPassed.GetValue() - LastTimeStamp) >= ResetDays
    ;Process the normall activation of the chopping block
    
    
    
    
    ;When the processing is done set the new time stamp value
    LastTimeStamp = GameDaysPassed.GetValue()
Else
    ; Display a message that the chopping block isn't ready for use
    NotReadyMsg.Show()
EndIf

 

Doesn't need to be the above way exactly but just some food for thought.

I can provide the script edited and to suite your needs, but where's the fun in that :tongue:

So I just thought I'd give a basic idea of how you can tackle it yourself :smile:

Link to comment
Share on other sites

Be quite simple in theory.

 

In brief:

Add 3 properties and 1 local variable to the script.

Do a quick check when activating if it's been x amount of days since last use, if not then display a message to say chopping block is depleted.

If it's been greater then x days then process the activation.

 

3 Properties and a local variable to add:

First property would be for so you can get the Game Days passed, which is a native game global variable.

So you would add to the script and fill it in CK (Auto-Fill will fill this property for you):

GlobalVariable Property GameDaysPassed Auto

Second Property to add would be a float value of How many game days you want to specify before it can be used again:

Float Property ResetDays = 30.0 Auto

I gave it a default value of 30 days, but you can a fill a value in CK to how ever many days you'd want before it resets.

 

Third property would be a Message to display when the user activates the chopping block and it's not ready to be used:

Message Property NotReadyMsg Auto

Lastly a local variable that we use to store a time stamp so you can check if the days passed is less or more then the require reset days:

Float LastTimeStamp

Now fit a small check into the script when the copping block is activated:

If (GameDaysPassed.GetValue() - LastTimeStamp) >= ResetDays
    ;Process the normall activation of the chopping block
    
    
    
    
    ;When the processing is done set the new time stamp value
    LastTimeStamp = GameDaysPassed.GetValue()
Else
    ; Display a message that the chopping block isn't ready for use
    NotReadyMsg.Show()
EndIf

Doesn't need to be the above way exactly but just some food for thought.

I can provide the script edited and to suite your needs, but where's the fun in that :tongue:

So I just thought I'd give a basic idea of how you can tackle it yourself :smile:

 

Thank you very much! :D

 

So far I have edited the script to this:

 

 

Scriptname ResourceFurnitureScript2 extends ObjectReference  Conditional
{script for furniture which the player can use to get resources}


formlist Property requiredItemList Auto  
{required for player to use - optional}

Message Property FailureMessage Auto  
{Message to say why you can't use this without RequiredWeapon}

MiscObject Property Resource Auto  
{what you get from using this furniture}

int Property ResourceCount = 1 Auto
{how many resources you get per use}

int property MaxResourcePerActivation = 6 auto
{How many times can this object be used before the player has to re-activate?}

int counter
; count up how many resources have been gathered on this go.

faction property CurrentFollowerFaction auto
{Used to handle player followers using the furniture object}

objectReference property NPCfollower auto hidden
{hidden property to track followers who used this}

GlobalVariable Property GameDaysPassed Auto

Float Property ResetDays = 30.0 Auto

Message Property NotReadyMsg Auto

Float LastTimeStamp

Event OnLoad()
    BlockActivation(true)
endEvent

Event OnUnload()
    ; safety measure
    UnregisterForEvents(game.getplayer())
    if NPCfollower
        UnregisterForEvents(NPCfollower)
    endif
endEvent

auto STATE normal
Event OnActivate(ObjectReference akActionRef)
    if (GameDaysPassed.GetValue() - LastTimeStamp) >= ResetDays
        ;Process the normal activation of the chopping block
    
        gotoState("busy")
    ;     debug.trace(self + "OnActivate")
        if akActionRef == Game.GetPlayer()  || (akActionRef as actor).isInFaction(CurrentFollowerFaction)
    ;        debug.trace("akActionRef is either player or a follower")
            if (akActionRef as actor) != game.getPlayer()
    ;             debug.trace("It's a follower - store in NPCfollower property")
                ; if not the player, must be the follower
                NPCfollower = akActionRef
            endif
            bool allowActivation = true
            ; check if player has required item
            if requiredItemList
                if akActionRef.GetItemCount(requiredItemList) == 0
                    if akActionRef == game.getPlayer()
                        ; only require the axe item for the player
                        allowActivation = false
    ;                     debug.trace("allowActivation = "+allowActivation)
                        FailureMessage.Show()
                    endif
                endif
            endif

            if allowActivation
                RegisterForEvents(akActionRef)
    ;             debug.trace(self + "player/follower activation START")
                Activate(akActionRef, true)
    ;             debug.trace(self + "player/follower activation END")
            endif
        else
    ;         ;debug.trace(self + "non-follower NPC activation START")
            ; just activate it
            Activate(akActionRef, true)
    ;         ;debug.trace(self + "non-follower NPC activation END")
        endif
        gotoState("normal")
        
        ;When the processing is done set the new time stamp value
        LastTimeStamp = GameDaysPassed.GetValue()
    else
        ;Display a message that the chopping block isn't ready for use
    NotReadyMsg.Show()
    endIf
endEvent
endState

STATE busy
    ; do nothing
endState

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
;     debug.trace(self + ": animation event received=" + asEventName)
    if asEventName == "AddToInventory"
        akSource.AddItem(Resource, ResourceCount)
        ; increment counter by however many items we just received
;         debug.trace("Pre-add counter = "+counter)
        counter = (counter + resourceCount)
;         debug.trace("Post-add counter = "+counter)
        if counter >= MaxResourcePerActivation
            ; if we've bagged our limit, kick the player out.  Reset timer for next activation
;             debug.trace("Woodpile - player has gotten "+counter+" logs this go.  Kicking out.")
            counter = 0
            (akSource as actor).PlayIdle(IdleWoodchopExit)
            unregisterForEvents(akSource)
        endif
    elseif asEventName == "IdleFurnitureExit"
;         debug.trace("Resource Object Unregistering: "+self)
        ; reset the counter if I exit manually
        counter = 0
        UnregisterForEvents(akSource)
    endif
endEvent

bool isRegisteredForEvents = false

function RegisterForEvents(objectReference whoToRegister)
    ; centralize this
    isRegisteredForEvents = true
    RegisterForAnimationEvent(whoToRegister, "AddToInventory")
    RegisterForAnimationEvent(whoToRegister, "SoundPlay . NPCHumanWoodChop")
    RegisterForAnimationEvent(whoToRegister, "IdleFurnitureExit")
endFunction

function UnregisterForEvents(objectReference whoToUnregister)
    ; centralize this
    
    ; It is perfectly safe to unregister for events you never registered for, however
    ; this function is called as part of OnUnload, and if this object isn't persistent
    ; then it may be deleted by the time OnUnload runs, and these function calls will
    ; fail. Since RegisterForAnimationEvent persists us, we know it will be safe to
    ; call Unregister if we've previously Registered, even if called as a part of
    ; OnUnload
    if isRegisteredForEvents
        isRegisteredForEvents = false
        UnRegisterForAnimationEvent(whoToUnregister, "AddToInventory")
        UnRegisterForAnimationEvent(whoToUnregister, "IdleFurnitureExit")
    endif
endFunction

Idle Property IdleWoodchopExit  Auto 

 

However, when I try to activate the woodchopping block now, I always get the "Not Ready" message. I'm a little bit unsure where to place the first and second part of the small check.

Link to comment
Share on other sites

Easy enough.
Because you haven't set a LastTimeStamp, you need to set one for it to actually be able to compare against.
Other wise the LastTimeStamp would always be 0.0.
So you add a one off LastTimeStamp to get the ball rolling eg:

Scriptname ResourceFurnitureScript2 extends ObjectReference  Conditional
{script for furniture which the player can use to get resources}

formlist Property requiredItemList Auto  
{required for player to use - optional}

Message Property FailureMessage Auto  
{Message to say why you can't use this without RequiredWeapon}

MiscObject Property Resource Auto  
{what you get from using this furniture}

int Property ResourceCount = 1 Auto
{how many resources you get per use}

int property MaxResourcePerActivation = 6 auto
{How many times can this object be used before the player has to re-activate?}

int counter
; count up how many resources have been gathered on this go.

faction property CurrentFollowerFaction auto
{Used to handle player followers using the furniture object}

objectReference property NPCfollower auto hidden
{hidden property to track followers who used this}

GlobalVariable Property GameDaysPassed Auto

Float Property ResetDays = 30.0 Auto

Message Property NotReadyMsg Auto

Float LastTimeStamp
Bool bFirstTimeStamp ;<--- Added for first time run

Event OnLoad()
    BlockActivation(true)
    
    ; Only one time as we havent used the Chopping block then you don't have a LastTimeStamp and it will always be 0.0
    If !bFirstTimeStamp
        bFirstTimeStamp = !bFirstTimeStamp
        LastTimeStamp = (GameDaysPassed.GetValue() - ResetDays)
    EndIf
endEvent

Event OnUnload()
    ; safety measure
    UnregisterForEvents(game.getplayer())
    if NPCfollower
        UnregisterForEvents(NPCfollower)
    endif
endEvent

auto STATE normal
Event OnActivate(ObjectReference akActionRef)
    gotoState("busy")
    if (GameDaysPassed.GetValue() - LastTimeStamp) >= ResetDays
        ;Process the normal activation of the chopping block
    
        
    ;     debug.trace(self + "OnActivate")
        if akActionRef == Game.GetPlayer()  || (akActionRef as actor).isInFaction(CurrentFollowerFaction)
    ;        debug.trace("akActionRef is either player or a follower")
            if (akActionRef as actor) != game.getPlayer()
    ;             debug.trace("It's a follower - store in NPCfollower property")
                ; if not the player, must be the follower
                NPCfollower = akActionRef
            endif
            bool allowActivation = true
            ; check if player has required item
            if requiredItemList
                if akActionRef.GetItemCount(requiredItemList) == 0
                    if akActionRef == game.getPlayer()
                        ; only require the axe item for the player
                        allowActivation = false
    ;                     debug.trace("allowActivation = "+allowActivation)
                        FailureMessage.Show()
                    endif
                endif
            endif

            if allowActivation
                RegisterForEvents(akActionRef)
    ;             debug.trace(self + "player/follower activation START")
                Activate(akActionRef, true)
    ;             debug.trace(self + "player/follower activation END")
            endif
        else
    ;         ;debug.trace(self + "non-follower NPC activation START")
            ; just activate it
            Activate(akActionRef, true)
    ;         ;debug.trace(self + "non-follower NPC activation END")
        endif
        
        
        ;When the processing is done set the new time stamp value
        LastTimeStamp = GameDaysPassed.GetValue()
    else
        ;Display a message that the chopping block isn't ready for use
        NotReadyMsg.Show()
    endIf
    gotoState("normal")
endEvent
endState

STATE busy
    ; do nothing
endState

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
;     debug.trace(self + ": animation event received=" + asEventName)
    if asEventName == "AddToInventory"
        akSource.AddItem(Resource, ResourceCount)
        ; increment counter by however many items we just received
;         debug.trace("Pre-add counter = "+counter)
        counter = (counter + resourceCount)
;         debug.trace("Post-add counter = "+counter)
        if counter >= MaxResourcePerActivation
            ; if we've bagged our limit, kick the player out.  Reset timer for next activation
;             debug.trace("Woodpile - player has gotten "+counter+" logs this go.  Kicking out.")
            counter = 0
            (akSource as actor).PlayIdle(IdleWoodchopExit)
            unregisterForEvents(akSource)
        endif
    elseif asEventName == "IdleFurnitureExit"
;         debug.trace("Resource Object Unregistering: "+self)
        ; reset the counter if I exit manually
        counter = 0
        UnregisterForEvents(akSource)
    endif
endEvent

bool isRegisteredForEvents = false

function RegisterForEvents(objectReference whoToRegister)
    ; centralize this
    isRegisteredForEvents = true
    RegisterForAnimationEvent(whoToRegister, "AddToInventory")
    RegisterForAnimationEvent(whoToRegister, "SoundPlay . NPCHumanWoodChop")
    RegisterForAnimationEvent(whoToRegister, "IdleFurnitureExit")
endFunction

function UnregisterForEvents(objectReference whoToUnregister)
    ; centralize this
    
    ; It is perfectly safe to unregister for events you never registered for, however
    ; this function is called as part of OnUnload, and if this object isn't persistent
    ; then it may be deleted by the time OnUnload runs, and these function calls will
    ; fail. Since RegisterForAnimationEvent persists us, we know it will be safe to
    ; call Unregister if we've previously Registered, even if called as a part of
    ; OnUnload
    if isRegisteredForEvents
        isRegisteredForEvents = false
        UnRegisterForAnimationEvent(whoToUnregister, "AddToInventory")
        UnRegisterForAnimationEvent(whoToUnregister, "IdleFurnitureExit")
    endif
endFunction

Idle Property IdleWoodchopExit  Auto
Link to comment
Share on other sites

This is the final script I came up with.

 

 

 

 

Scriptname ResourceFurnitureScript2 extends ObjectReference  Conditional
{script for furniture which the player can use to get resources}


formlist Property requiredItemList Auto  
{required for player to use - optional}

Message Property FailureMessage Auto  
{Message to say why you can't use this without RequiredWeapon}

MiscObject Property Resource Auto  
{what you get from using this furniture}

int Property ResourceCount = 1 Auto
{how many resources you get per use}

int property MaxResourcePerActivation = 6 auto
{How many times can this object be used before the player has to re-activate?}

int counter
; count up how many resources have been gathered on this go.

faction property CurrentFollowerFaction auto
{Used to handle player followers using the furniture object}

objectReference property NPCfollower auto hidden
{hidden property to track followers who used this}

GlobalVariable Property GameDaysPassed Auto

Float Property ResetDays = 30.0 Auto

Message Property NotReadyMsg Auto

Float LastTimeStamp

Bool bFirstTimeStamp ;<--- Added for first time run

Event OnLoad()
    BlockActivation(true)
    
        ; Only one time as we haven't used the Chopping block then you don't have a LastTimeStamp and it will always be 0.0
    If !bFirstTimeStamp
        bFirstTimeStamp = !bFirstTimeStamp
        LastTimeStamp = (GameDaysPassed.GetValue() - ResetDays)
    EndIf
endEvent

Event OnUnload()
    ; safety measure
    UnregisterForEvents(game.getplayer())
    if NPCfollower
        UnregisterForEvents(NPCfollower)
    endif
endEvent

auto STATE normal

Event OnActivate(ObjectReference akActionRef)
    
    
    gotoState("busy")
;     debug.trace(self + "OnActivate")

    
        if akActionRef == Game.GetPlayer()  || (akActionRef as actor).isInFaction(CurrentFollowerFaction)
    ;        debug.trace("akActionRef is either player or a follower")
            if (akActionRef as actor) != game.getPlayer()
    ;             debug.trace("It's a follower - store in NPCfollower property")
                ; if not the player, must be the follower
                NPCfollower = akActionRef
            endif
            bool allowActivation = true
            ; check if player has required item
            if requiredItemList
                if akActionRef.GetItemCount(requiredItemList) == 0
                    if akActionRef == game.getPlayer()
                        ; only require the axe item for the player
                        allowActivation = false
    ;                     debug.trace("allowActivation = "+allowActivation)
                        FailureMessage.Show()
                    endif
                endif
            endif
;I added your lines here, it seems to work great. I also added allowActivation=false and debug.trace("allowActivation = "+allowActivation)
            if (GameDaysPassed.GetValue() - LastTimeStamp) >= ResetDays
                LastTimeStamp = GameDaysPassed.GetValue()
            else
                allowActivation = false
    ;             debug.trace("allowActivation = "+allowActivation)
                NotReadyMsg.Show()
            endIf
            
            if allowActivation
                RegisterForEvents(akActionRef)
    ;             debug.trace(self + "player/follower activation START")
                Activate(akActionRef, true)
    ;             debug.trace(self + "player/follower activation END")
            endif
        else
    ;         ;debug.trace(self + "non-follower NPC activation START")
            ; just activate it
            Activate(akActionRef, true)
    ;         ;debug.trace(self + "non-follower NPC activation END")
        endif
        
        

        
    gotoState("normal")
endEvent
endState

STATE busy
    ; do nothing
endState

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
;     debug.trace(self + ": animation event received=" + asEventName)
    if asEventName == "AddToInventory"
        akSource.AddItem(Resource, ResourceCount)
        ; increment counter by however many items we just received
;         debug.trace("Pre-add counter = "+counter)
        counter = (counter + resourceCount)
;         debug.trace("Post-add counter = "+counter)
        if counter >= MaxResourcePerActivation
            ; if we've bagged our limit, kick the player out.  Reset timer for next activation
;             debug.trace("Woodpile - player has gotten "+counter+" logs this go.  Kicking out.")
            counter = 0
            (akSource as actor).PlayIdle(IdleWoodchopExit)
            unregisterForEvents(akSource)
        endif
    elseif asEventName == "IdleFurnitureExit"
;         debug.trace("Resource Object Unregistering: "+self)
        ; reset the counter if I exit manually
        counter = 0
        UnregisterForEvents(akSource)
    endif
endEvent

bool isRegisteredForEvents = false

function RegisterForEvents(objectReference whoToRegister)
    ; centralize this
    isRegisteredForEvents = true
    RegisterForAnimationEvent(whoToRegister, "AddToInventory")
    RegisterForAnimationEvent(whoToRegister, "SoundPlay . NPCHumanWoodChop")
    RegisterForAnimationEvent(whoToRegister, "IdleFurnitureExit")
endFunction

function UnregisterForEvents(objectReference whoToUnregister)
    ; centralize this
    
    ; It is perfectly safe to unregister for events you never registered for, however
    ; this function is called as part of OnUnload, and if this object isn't persistent
    ; then it may be deleted by the time OnUnload runs, and these function calls will
    ; fail. Since RegisterForAnimationEvent persists us, we know it will be safe to
    ; call Unregister if we've previously Registered, even if called as a part of
    ; OnUnload
    if isRegisteredForEvents
        isRegisteredForEvents = false
        UnRegisterForAnimationEvent(whoToUnregister, "AddToInventory")
        UnRegisterForAnimationEvent(whoToUnregister, "IdleFurnitureExit")
    endif
endFunction

Idle Property IdleWoodchopExit  Auto 

 

 

 

I looked at the failmessage when you don't have an axe and added your lines in a similar fashion.

 

I also added I also added allowActivation=false and debug.trace("allowActivation = "+allowActivation). I'm not 100% sure what they do, though. (Is it safe to do this?) But it seems to work fine, tbh.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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