Scripting Advice for a fumbling begginer

Post » Wed Jun 20, 2012 6:37 am

With permission from Elec0 I've been using a script he wrote to make a craft-able furniture/crafting stations mod. I've got it all done, the only hitch I've had is getting his script to work with the wood chopping block activator.

The script is:
Scriptname E0ActivatorSCR extends ObjectReference  ; Try and remove the activator, since we shouldn't need it anymore.MiscObject property itemToAdd autoEvent OnLoad()	BlockActivation()	EndEventEvent OnActivate(ObjectReference activator)	if Game.GetPlayer().IsSneaking() == True		; This works perfectly		Game.GetPlayer().AddItem(itemToAdd, 1)		Disable()		Return	Else		Activate(Game.GetPlayer(), true)	EndIfEndEvent

When added in addition to the wood cutting blocks script the block could be placed/removed whilst sneaking as it was supposed to and would play the animations properly on activation whilst standing, but wouldn't check for the presence of a woodcutter's axe or add resources.

Figuring the problem was that the new script was blocking the old one from running, I figured I should probably just make a new script and combine them. At which point I ran aground of my woefully non-existent scripting skills.

What I've got at the moment:
Scriptname e0activatorscrWoodChop extends ObjectReference  MiscObject property itemToAdd autoformlist 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()    EndEventEvent OnActivate(ObjectReference activator)    if Game.GetPlayer().IsSneaking() == True        ; This works perfectly        Game.GetPlayer().AddItem(itemToAdd, 1)        Disable()        Return    Else        Activate(Game.GetPlayer(), true)    EndIfEndEventEvent OnUnload()    ; safety measure    UnregisterForEvents(game.getplayer())    if NPCfollower        UnregisterForEvents(NPCfollower)    endifendEventauto STATE normalEvent 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")endEventendStateSTATE busy    ; do nothingendStateEvent 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)    endifendEventbool isRegisteredForEvents = falsefunction RegisterForEvents(objectReference whoToRegister)    ; centralize this    isRegisteredForEvents = true    RegisterForAnimationEvent(whoToRegister, "AddToInventory")    RegisterForAnimationEvent(whoToRegister, "SoundPlay . NPCHumanWoodChop")    RegisterForAnimationEvent(whoToRegister, "IdleFurnitureExit")endFunctionfunction 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")    endifendFunctionIdle Property IdleWoodchopExit  Auto

The origonal part of the script runs just fine, but Elec0's pick up/put down script isn't working. Can some kind and merciful soul tell me what I'm doing wrong?
User avatar
Eliza Potter
 
Posts: 3481
Joined: Mon Mar 05, 2007 3:20 am

Post » Wed Jun 20, 2012 12:40 pm

The problem is that you have two OnActivate events going on. The first one is the one you copied from Elec0's script, and the second one is from the original script. The original script must be blocking the one from Elec0's script. I can combine them, but that doesn't mean it'll work.

I suspect that Elec0's script works by disabling something (call it activator A) and giving the player a dummy item (call it item A). Then when you drop item A from your inventory, it uses PlaceAtMe to create a new instance of activator A at your location. So not only do you have to fix the script for the chopping block, you also need to change the script on the misc item.

Even then, I'm not sure I would like this method, since it would mean leaving disabled chopping blocks all over the place... Anyway, this is the correct combined script of what you put up:

Spoiler
Scriptname e0activatorscrWoodChop extends ObjectReference  MiscObject property ItemToAdd auto{dummy object placed in inventory in order to move the block around}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()EndEventAuto State Normal    Event OnActivate(ObjectReference akActionRef)        GoToState("Busy");        debug.trace(self + "OnActivate")        if (akActionRef == Game.GetPlayer());            debug.trace("akActionRef is player")            if ((akActionRef as Actor).IsSneaking());                check to see if the player is sneaking                akActionRef.AddItem(ItemToAdd, 1);                add the dummy item to the player                Disable();                disable the block so the player can no longer see it                GoToState("Normal")                Return            endif        elseif (akActionRef as Actor).IsInFaction(CurrentFollowerFaction));            debug.trace("akActionRef is a follower")            NPCfollower = akActionRef        else;            debug.trace(self + "non-follower NPC activation START");            just activate it            Activate(akActionRef, true);            debug.trace(self + "non-follower NPC activation END")            GoToState("Normal")            Return        endif;        the rest of the OnActivate event only runs for player or follower            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        GoToState("Normal")    EndEventEndStateState Busy;    do nothingEndStateEvent 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)    endifendEventbool isRegisteredForEvents = falsefunction RegisterForEvents(objectReference whoToRegister)    ; centralize this    isRegisteredForEvents = true    RegisterForAnimationEvent(whoToRegister, "AddToInventory")    RegisterForAnimationEvent(whoToRegister, "SoundPlay . NPCHumanWoodChop")    RegisterForAnimationEvent(whoToRegister, "IdleFurnitureExit")endFunctionfunction 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")    endifendFunctionIdle Property IdleWoodchopExit  Auto
User avatar
Alex Vincent
 
Posts: 3514
Joined: Thu Jun 28, 2007 9:31 pm

Post » Wed Jun 20, 2012 6:06 am

Thanks for the help! As you can tell, I'm at that embarrassing stage where I know enough to be able to work with scripts, but not nearly enough to actually know why I'm doing what I'm doing. :P

Even then, I'm not sure I would like this method, since it would mean leaving disabled chopping blocks all over the place... Anyway, this is the correct combined script of what you put up:

That... had not occurred to me at all. Using this method in the long run would probably lead to massive save game bloating wouldn't it? Maybe I should look into seeing whether a script that simply moved a referenced object between cells rather than spawning a brand new instance every-time you use it would work. Thanks for the heads up on that.
User avatar
Veronica Martinez
 
Posts: 3498
Joined: Tue Jun 20, 2006 9:43 am

Post » Wed Jun 20, 2012 1:08 am

Well, that's probably just me being over-reactive. I doubt anyone would be using it so much to have more than 100 or so chopping blocks. The bloat would be unnoticeable.

I was just thinking about what it would do to NPCs if you disable the chopping blocks. What would Faendal or Sigurd do if their chopping blocks disappeared?
User avatar
Ells
 
Posts: 3430
Joined: Thu Aug 10, 2006 9:03 pm

Post » Wed Jun 20, 2012 6:58 am

Hopefully that won't be a problem, I'm only going to add the script to new benches that can be created at the forge. Being able to run into town and nick someones anvil would be hilarious, but probably a little silly. :D
User avatar
Dan Endacott
 
Posts: 3419
Joined: Fri Jul 06, 2007 9:12 am


Return to V - Skyrim