AndrealphusVIII Posted July 24, 2015 Share Posted July 24, 2015 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 More sharing options...
sLoPpYdOtBiGhOlE Posted July 25, 2015 Share Posted July 25, 2015 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 AutoSecond 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 AutoI 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 More sharing options...
AndrealphusVIII Posted July 25, 2015 Author Share Posted July 25, 2015 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 AutoSecond 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 AutoI 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 AutoLastly 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 LastTimeStampNow 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() EndIfDoesn'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 More sharing options...
sLoPpYdOtBiGhOlE Posted July 25, 2015 Share Posted July 25, 2015 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 More sharing options...
AndrealphusVIII Posted July 25, 2015 Author Share Posted July 25, 2015 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 More sharing options...
sLoPpYdOtBiGhOlE Posted July 25, 2015 Share Posted July 25, 2015 Looks better the way you have done it then the way was , good job :) If it's doing what you wanted then I can't see any problems the way you heave it. Link to comment Share on other sites More sharing options...
Recommended Posts