Author Topic: Item script firing twice.  (Read 887 times)

Legacy_Weye

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Item script firing twice.
« on: February 07, 2014, 08:22:05 pm »


               Hi, I'm hoping someone here can help me.
I'm using the Rod of Fast Buffing from the NWN Vault in the module Tortured Hearts. I got the item and its script into the game by importing it into a module with the toolset, and then copying the temporary files into the override folder.  So I have three files in my override: the nss, ncs, and uti.

Problem is, everything the rod does it does twice. I will paste the NSS file here, but I have a feeling the problem is not the script itself since I haven't seen this problem mentioned anywhere else.  Any ideas how to fix this?

Thanks.  Here's the script:

Edit: Did a little more testing.  In the original campaign the item will not store spells at all.  I get invalid target errors.  Also, I started a new game in Tortured Hearts and the item fires its script twice just like in my save game.

//::///////////////////////////////////////////////
//::Rod of Fast Buffing Item Event Script
/*
   This is the event script for the rod of fast
   buffing. This rod allows casters to group
   all their buffing spells into a single action
*/
//:://////////////////////////////////////////////

#include "x2_inc_switches"

//showing spell names is a 2da file hit. When storing
//a lot of spells this can cause a significant delay
//When this value is false it will just show spell
//ID numbers.
const int knShowSpellName = TRUE;

//used to store the number of spells on the rod
const string ksNumSpells = "NumSpells";
//used as a base to store a spell ID to cast
const string ksCastSpellId = "CastSpells";
//stores the spell name when you store a spell.
const string ksCastSpellName = "SpellName";

//clears out the spells from the Rod
void ClearRodSpells(object oItem);

//returns true if oTarget is a member of the oPC's party
int GetIsPartyMember(object oPC, object oTarget);

void main()
{
   int nEvent = GetUserDefinedItemEventNumber();

   object oPC;         //The caster
   object oItem;       //This item
   object oTarget;      //Target of Rod Use

   int nSpellId;       //Used to hold the ID of the current spell;
   int nNumOfSpells;   //Used to hold the current number of spells on the rod

   string strSpellName;//Used to hold the Spell Name

   int nResult = X2_EXECUTE_SCRIPT_CONTINUE;

   //this handles "use" or activation of item.
   if (nEvent ==  X2_ITEM_EVENT_ACTIVATE)
   {
       oItem = GetItemActivated();
       oPC = GetItemActivator();
       oTarget = GetItemActivatedTarget();

       //Disable use in combat
       if(GetIsInCombat(oPC))
       {
           FloatingTextStringOnCreature("Can't use rod in combat", oPC, FALSE);
           return;
       }

       //check if the rod is targeting itself and clear out spells if it is
       if(oItem == oTarget)
       {
           SendMessageToPC(oPC, "Clearing spells from Rod");
           ClearRodSpells(oItem);
           return;
       }

       if(!GetIsObjectValid(oTarget)
           || !GetIsPartyMember(oPC, oTarget))
       {
           SendMessageToPC(oPC, "The target is invalid");
           return;
       }

       //get number of spells stored
       nNumOfSpells = GetLocalInt(oItem, ksNumSpells);
       SendMessageToPC(oPC, " Attempting to fast cast " + IntToString(nNumOfSpells) + " spells.");

       //iterate through array of spells and store casting action
       int n;
       for(n = 1; n <= nNumOfSpells; n++)
       {
           //get spell id stored at location n
           nSpellId = GetLocalInt(oItem, ksCastSpellId + IntToString(n));

           //Get the name of the spell stored at location n
           strSpellName = GetLocalString(oItem, ksCastSpellName + IntToString(n));

           SendMessageToPC(oPC, "Casting spell "
                           + strSpellName
                           + " at postion "
                           + IntToString(n)
                           + " on item");

           if(0 != nSpellId //if there was a valid spell id stored
              && 1 <= GetHasSpell(nSpellId, oPC)) //and the caster has access to the spell
           {
               //Store cast action. The key here is to set cheatcasting
               //to false and level to 0. This will cause the caster
               //to cast the spell himself using the first available
               //slot.
               AssignCommand(oPC,
               ActionCastSpellAtObject(nSpellId
                                       , oTarget
                                       , METAMAGIC_ANY
                                       , FALSE
                                       , 0
                                       , PROJECTILE_PATH_TYPE_DEFAULT
                                       , TRUE));
           }
       }
   } //This Event Handles storing the spells
   else if (nEvent ==  X2_ITEM_EVENT_SPELLCAST_AT)
   {
       oItem = GetSpellTargetObject();
       nSpellId = GetSpellId();
       oPC = OBJECT_SELF;
       nNumOfSpells = GetLocalInt(oItem, ksNumSpells) + 1;

       SetLocalInt(oItem, ksNumSpells , nNumOfSpells);
       SetLocalInt(oItem, ksCastSpellId + IntToString(nNumOfSpells), nSpellId);

       strSpellName = (knShowSpellName)
                       ? Get2DAString("spells", "Label", nSpellId)
                       : IntToString(nSpellId);

       SetLocalString(oItem, ksCastSpellName + IntToString(nNumOfSpells), strSpellName);

       SendMessageToPC(oPC, "Storing "
                         + strSpellName
                         + " at postion "
                         + IntToString(nNumOfSpells)
                         + " on item");

       nResult = X2_EXECUTE_SCRIPT_END;

   }

   //Pass the return value back to the calling script
   SetExecutedScriptReturnValue(nResult);
}


//returns true if oTarget is a member of the oPC's party
int GetIsPartyMember(object oPC, object oTarget)
{
   if(oPC == oTarget) return TRUE;

   int nPartyMember = FALSE;
   object oPartyMember = GetFirstFactionMember(oPC, FALSE);
   while(GetIsObjectValid(oPartyMember) == TRUE)
   {
       if(oPartyMember == oTarget)
       {
           nPartyMember = TRUE;
           break;
       }
       oPartyMember = GetNextFactionMember(oPC, FALSE);
   }

   return nPartyMember;
}

//clears out the spells from the Rod
void ClearRodSpells(object oItem)
{
  //get number of spells stored
   int nNumOfSpells = GetLocalInt(oItem, ksNumSpells);

   //iterate through array of spells and delete the local variable
   int n;
   for(n = 1; n <= nNumOfSpells; n++)
   {
       //Delete spell id stored at location n
       DeleteLocalInt(oItem, ksCastSpellId + IntToString(n));

       //Delete the name of the spell stored at location n
       DeleteLocalString(oItem, ksCastSpellName + IntToString(n));
   }
   DeleteLocalInt(oItem, ksNumSpells);
}
               
               

               


                     Modifié par Weye, 07 février 2014 - 08:38 .
                     
                  


            

Legacy__Guile

  • Hero Member
  • *****
  • Posts: 1308
  • Karma: +0/-0
Item script firing twice.
« Reply #1 on: February 08, 2014, 06:47:16 am »


               Without looking at your script (cause I know it works correctly), I'd say the issue is, you probably have 2 OnActivateItem Module Event Scripts Firing...

BTW, I created a really good fast buffing system, it can either use a chat command or an item, it requires no storing spells and just has the caster cast all of their buffs that they have memorized (using the best buff they have stored), e.g. Great Spell Mantle instead of Spell Mantle...

(NOTE there is a bug in nwn, Bards / Paladins / Ranger Spells are always cast at level 1 no matter what.)

Fast Buffing By Genisys
               
               

               


                     Modifié par _Guile, 08 février 2014 - 06:51 .
                     
                  


            

Legacy_Weye

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Item script firing twice.
« Reply #2 on: February 09, 2014, 12:08:33 am »


               Thanks for responding, Guile.  You are right, the script is fine.  The same problem occurs with another custom item I just installed in the override folder (wand of mana "rest-rod" http://social.biowar...ect/4139/#files).  It fires its Unique Power script twice.  Any ideas how to fix it?

I'm sure your fast buff mod is great but I don't think it can buff companions?
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Item script firing twice.
« Reply #3 on: February 09, 2014, 02:33:36 am »


               We need to see more scripts.

Post
nw_s3_actitem01
And your on activate item event script.

also supply the name of the script for the Tag Based item.
and the Tag of the item if it is different,   (  If you are using a prefix for tag based items.) 
               
               

               


                     Modifié par Lightfoot8, 09 février 2014 - 02:35 .
                     
                  


            

Legacy_Weye

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Item script firing twice.
« Reply #4 on: February 09, 2014, 03:31:56 am »


               Lightfoot,
I'm afraid I'm not sure what you want me to do.  I can't find a nw_s3_actitem01 file anywhere except inside data\\scripts.bif, which I assume is the default one (pasted below).  What is the activate item event script if not what I pasted in my first post?  I'm afraid I'm not familiar with the tag system you speak of.

//::///////////////////////////////////////////////
//:: Actuvate Item Script
//:: NW_S3_ActItem01
//:: Copyright © 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
   This fires the event on the module that allows
   for items to have special powers.
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Dec 19, 2001
//:://////////////////////////////////////////////

void main()
{
   object oItem = GetSpellCastItem();
   object oTarget = GetSpellTargetObject();
   location lLocal = GetSpellTargetLocation();

   SignalEvent(GetModule(), EventActivateItem(oItem, lLocal, oTarget));
}
               
               

               
            

Legacy_Weye

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Item script firing twice.
« Reply #5 on: February 09, 2014, 04:04:05 am »


               In the module properties of Tortured Hearts, the OnActivateItem script is set to: x2_mod_def_act
I found this in x2_mod_def_act.nss:

 SetUserDefinedItemEventNumber(X2_ITEM_EVENT_ACTIVATE);
 ExecuteScript( GetUserDefinedItemEventScriptName(GetItemActivated()), OBJECT_SELF );



    // * Generic Item Script Execution Code
    // * If MODULE_SWITCH_EXECUTE_TAGBASED_SCRIPTS is set to TRUE on the module,
    // * it will execute a script that has the same name as the item's tag
    // * inside this script you can manage scripts for all events by checking against
    // * GetUserDefinedItemEventNumber(). See x2_it_example.nss
    if (GetModuleSwitchValue(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS) == TRUE)
    {
       SetUserDefinedItemEventNumber(X2_ITEM_EVENT_ACTIVATE);
       int nRet =   ExecuteScriptAndReturnInt(GetUserDefinedItemEventScriptName(oACT_ITEM),OBJECT_SELF);
       if (nRet == X2_EXECUTE_SCRIPT_END)
       {
          return;
       }

    }

}
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Item script firing twice.
« Reply #6 on: February 09, 2014, 04:21:17 am »


               Looks like you found the problem.  Two ExecuteScript() calls to presumably the same script.  If oACT_ITEM is the same as GetItemActivated(), there is no need for one of the two calls.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Item script firing twice.
« Reply #7 on: February 09, 2014, 04:21:43 am »


               

Weye wrote...

Lightfoot,
I'm afraid I'm not sure what you want me to do.  I can't find a nw_s3_actitem01 file anywhere except inside datascripts.bif, which I assume is the default one (pasted below).  What is the activate item event script if not what I pasted in my first post?  I'm afraid I'm not familiar with the tag system you speak of.


nw_s3_actitem01
The one you posted is most likely the one you are using,  unless you have a modified one.   The only way to really tell it to open up the script editor and open the version of the script that the module is using.   You may  have to click the "All Resources in module" option in order to find it. 

The script you posted is the Tag Based script.   The Actvate Item Event script will be listed in the modules properties.  under OnActivateItem on the Events tab. 



'Image
               
               

               
            

Legacy_MrZork

  • Hero Member
  • *****
  • Posts: 1643
  • Karma: +0/-0
Item script firing twice.
« Reply #8 on: February 09, 2014, 06:05:38 am »


               (It really is a shame that the code tags on this forum don't function well. Makes it tough to tell when people are posting a whole script or just quoting lines from within some code or quoting some lines from within several scripts, etc.)

But, it looks like someone followed some directions for enabling tag-based scripting to an OnActivate handler that already had it enabled. If the code posted above is all inside the same script, then removing the first two lines will likely fix the double-firing issue.
               
               

               
            

Legacy_Weye

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Item script firing twice.
« Reply #9 on: February 09, 2014, 05:19:28 pm »


               Sounds promising, but how do I implement the fixed file?  I tried editing the script in the toolset, compiling it (clicked compile and save), then copying the nss and ncs from the temp folder into my override, but nothing changed in my game.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Item script firing twice.
« Reply #10 on: February 09, 2014, 07:09:09 pm »


               the override folder will not override anything in the module or in haks.    

If the script is not in a hak,  just compile it in the module and leave it there.    

If the script is in a hak replace the version in the hak with the new version.
               
               

               
            

Legacy_Weye

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Item script firing twice.
« Reply #11 on: February 09, 2014, 07:41:21 pm »


               OK, I've confirmed that removing those two lines in "Tortured Hearts I.mod" fixes the problem in a new game, but it did not affect my saved game.  Editing my .sav file as a .mod file caused the game to crash on loading the save.  Any way to get the fix into my save game?
               
               

               
            

Legacy_MrZork

  • Hero Member
  • *****
  • Posts: 1643
  • Karma: +0/-0
Item script firing twice.
« Reply #12 on: February 09, 2014, 08:10:15 pm »


               It can be done, but it can be slightly complicated. Basically, you need a utility that let's you replace the resource files in an erf file. Someone probably has a recommendation for a utility like that.

(I am assuming that there is one because it would be so useful for module makers who are looking to test fixes to scripts, items, etc. where it would be tedious to replay the module to the point where those things are testable every time a change is made to them. And, it would be useful for distributing such fixes and updates to beta testers so they don't have to replay too much to test if a fix to a bug they found is working.)

A while back, I wrote a utility to do that in python for my own use, but I hate writing GUIs, so you would need python installed to use it. Basically, you would need to run the following from a python command line.

>>> import ReadNWNModule
>>> SGName = r'C:\\Program Files (x86)\\games\\NeverwinterNights\\NWN\\saves\\000000 - quicksave\\Tortured Hearts I.sav'
>>> ReadNWNModule.AddReplaceERFResources(SGName,[r'C:\\Program Files (x86)\\games\\NeverwinterNights\\NWN\\modules\\temp0\\x2_mod_def_act.nss', r'C:\\Program Files (x86)\\games\\NeverwinterNights\\NWN\\modules\\temp0\\x2_mod_def_act.ncs', ])
Not complicated, but someone probably knows of a utility with a nicer user interface. You can see that the first line loads the python module, the second line sets your saved game filename, and the third line calls a function with that filename and a list of the resource files you are looking to replace in it (those files are usually in your module/temp0 folder if you have been recompiling scripts using the Toolset).

If you want to use the python utility, let me know and I will get it to you.
               
               

               


                     Modifié par MrZork, 09 février 2014 - 08:14 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Item script firing twice.
« Reply #13 on: February 09, 2014, 08:22:51 pm »


               The module is nothing more then an ERF file.  

A hak is also nothing more then an ERF file.  

You can use the hak pack editor from the utils folder to remove the old scripts from the saved game.

After that is done you can either add the new ons to the saved game using the hak editor or use the override folder.
               
               

               
            

Legacy_Weye

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Item script firing twice.
« Reply #14 on: February 09, 2014, 08:36:40 pm »


               Fantastic!  Got it working.  You guys rock.  I will post a message to the mod's creator about this bugfix.