Author Topic: Could use a lil help with a few scripts.  (Read 1281 times)

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« on: September 21, 2011, 08:52:47 pm »


               Hey all,
I have gotten a ton of help in the past from alot of you here on the boards, so I thought I would see if I could pick you all's brains a bit more? I have a few scripts I could use some help with, and would welcome any input. I will start with my current top priority.

We have tried 2 different ways at modifying defensive stance. This is the second attempt I will post first as if we can get this to work it would be much better than my first attempt. The idea behind this is that you use an object to use one of you DDDS uses per day, and it fires this script which gives the DD a HP boost based of DD level and Con modifier, in addition to 5% immunity to all dmg types per 10 DD levels. It works beautifully, but the problem is for some reason I have not been able to figure out it just stops working randomly (I can not figure out the exact conditions that cause this), and will not work again until the server is restarted. Any ideas about why this is happening, and how to fix it would be appreciated.

Thanks, Laz

#include "x2_i0_spells"
//#include "core_inc_post40"
void main()
{
  if(!GetUserDefinedItemEventNumber() == X2_ITEM_EVENT_ACTIVATE) return;
  object oPC = GetItemActivator();
  if(!GetHasFeat(FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE, oPC)) return;
  if(GetLocalInt(oPC, "DD") == TRUE)
  {
     FloatingTextStringOnCreature("Still in cool down", oPC, FALSE);
     return;
  }
  PlayVoiceChat(VOICE_CHAT_BATTLECRY1, oPC);
  int nclassLevel = GetLevelByclass(class_TYPE_DWARVENDEFENDER, oPC);
  int nPercent = nclassLevel/10 *5;
  int nHP = (nclassLevel + GetAbilityModifier(ABILITY_CONSTITUTION, oPC)) *10;
  effect eVis = EffectVisualEffect(VFX_DUR_AURA_PULSE_RED_YELLOW);
  effect eLink = EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, nPercent);
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_DIVINE, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_ELECTRICAL, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_FIRE, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_MAGICAL, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_NEGATIVE, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_PIERCING, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_POSITIVE, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SLASHING, nPercent));
  eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SONIC, nPercent));
  eLink = EffectLinkEffects(eLink, eVis);
  effect eHP = EffectTemporaryHitpoints(nHP);
  ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 60.0);
  ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHP, oPC, 60.0);
  DecrementRemainingFeatUses(oPC, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE);
  SetLocalInt(oPC, "DD", TRUE);
  DelayCommand(60.0, DeleteLocalInt(oPC, "DD"));

               
               

               
            

Legacy_Xardex

  • Sr. Member
  • ****
  • Posts: 414
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #1 on: September 21, 2011, 10:47:39 pm »


               It most likely is happening because for some reason your DelayCommand is interrupted. When server restarts, local ints from characters are wiped. This is why I decided not to use delay command but instead this:

"mod_time" - Name of the script, you can use whatever you like

// Returns current server time in seconds
int Time();

int Time()
{
    int iTime;
    int iH = FloatToInt(HoursToSeconds(1))/60; // Amount of minutes per hour
    iTime -= GetLocalInt(GetModule(), "time_zero");
    iTime += GetTimeSecond();
    iTime += GetTimeMinute()*60;
    iTime += GetTimeHour()*iH*60;
    iTime += GetCalendarDay()*24*iH*60;
    iTime += GetCalendarMonth()*28*24*iH*60;
    iTime += GetCalendarYear()*12*28*24*iH*60;
    return iTime;
}


Should be self explanatory. Put this to your module load event:
( And remember to include "mod_time" )

SetLocalInt(OBJECT_SELF, "time_zero", Time());


Now you can easily add cooldowns for any feats or items by including "mod_time" and doing this (using your script as example):

SetLocalInt(oPC, "DD", Time()+60;

And when you check for cooldown:

if (Time() < GetLocalInt(oPC, "DD")){}


One more thing... Remember to add the cooldowns always to something where they dont persist over server restarts, or they might not work as expected.



EDIT

Wait a moment...!
Can someone tell me will this overflow if year is 2220 or higher? (assuming iH is the default 2)
[ Unless im totally wrong... Doesn't nwn assign 32 bits for its ints? ]

Now that im thinking about it, I could remove the calendar year and it should work anytime... But then I would need to add a pseudo heartbeat with a delay of a YEAR to remove cooldowns. Or just assume a server restarts at least once every 11 days. Hmm. Im dumb. Moving 1 line to fix it. Bleeding my thoughts here....

The script should work fine now.':whistle:'

I guess it could fail if module calendar year is advanced by over 2220 years after server has started running... But I'll consider that an acceptable flaw.
<><>

               


                     Modifié par Xardex, 21 septembre 2011 - 10:18 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #2 on: September 21, 2011, 11:33:36 pm »


               Thank you for the suggestion Xardex. I will try that, if I can't get it to work as is, but couldn't I just remove the set/delete local interger functions if this is what is causing the problem? Since the buff only last one minute anyways, is it even necessary to have that?
               
               

               
            

Legacy_Axe_Murderer

  • Full Member
  • ***
  • Posts: 199
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #3 on: September 22, 2011, 02:16:22 am »


               You should probably ensure that should the percent computation come up zero, you don't apply all those effects.

Also you could simplify that computation from  x/10 *5  to x/2.

You might also consider turning on the cooldown even when they don't have the feat.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #4 on: September 22, 2011, 05:49:39 am »


               Not exactly sure what you mean Axe. The point is to apply all those effects (granted at only 5% per 10 DD lvls).

Wouldn't x/2 make it 5% per 2 DD lvls? That's not quite what we are going for.

If they dont have the feat, the cool down timer is irrelavant. In fact I am not too concerned about it in general. If a player wants to use all his/her DS in one shot (stacking) to become immune for one min, it's not a big deal. There is a 10 min rest timer on Av3, so that will leave them hard up for the other 9 min...
               
               

               
            

Legacy_Axe_Murderer

  • Full Member
  • ***
  • Posts: 199
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #5 on: September 22, 2011, 10:30:14 am »


               (x/10)*5 == (x*5)/10 == x*(5/10) == x*(1/2) == x/2
its the same thing just less math for the cpu to do...one division rather than both a division and a mult.
percent will end up always being half their DD level...which equates to 1% every 2 levels, 5% every 10.

There is however an integer division in there so if you're level 9 DD then percent will be zero if you do x/10*5 because 9/10 == 0 in integer math and that will get evaluated before the mult...maybe you wanted that, I was assuming you didn't. That's why I mentioned not applying the effects when it's zero.
               
               

               


                     Modifié par Axe_Murderer, 22 septembre 2011 - 11:13 .
                     
                  


            

Legacy_the.gray.fox

  • Full Member
  • ***
  • Posts: 214
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #6 on: September 22, 2011, 11:01:04 am »


               Hello.

Lazarus Magni wrote...

[...] The idea behind this is that you use an object to use one of you DDDS uses per day, and it fires this script which [...]


Can this object used to activate the DDDS expire
or be depleted, or otherwise be destroyed?
Would you reveal its exact nature, just so we are sure?


Anyway...
Barring the possibility that a 2nd script somewhere is secretly
SetlocalInt() "DD" on the PC, I too believe that the issued
DelayCommand() is being canceled.

But the exact why... I can not tell.
OBJECT_SELF therein is the Module -- right?


A workaround would be to AssignCommand() the DelayCommand()
to DeleteLocalInt() to the very PC. As the PC is constantly
around and constantly granted a high CPU slice, it is
guaranteed to carry it out.
(If this too fails, then you _do_ have a 2nd script interfering)


But your problem is worth investigation.
The Module, being indestructible, is not supposed to ever
drop any DelayCommand() issued to it.
Something sneaky is being at work here, you see.
I would run your script as-is for some time with a debug
output to state when the SetLocalInt() DeleteLocalInt() has been successfully
run (a wrapper function will do).
That should help you catch the "when" it stops working and,
from there, pin down the why.


-fox
               
               

               


                     Modifié par the.gray.fox, 22 septembre 2011 - 10:03 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #7 on: September 22, 2011, 08:38:57 pm »


               Thanks for your responses. My apologies Axe, I should probably look at what the variable is before trying to interpret an equation. Indeed you'er correct, although I believe the original intent of the /10 was to make it so DDs only got this bonus every 10 levels. The more I think on it I like the 1% every 2 levels better so I will change it to that.

Fox, the object is an unlimited use per day cast spell unique power self only item. It can not be depleted. I believe your on to something here though, I noticed in the log right before it stops working this occurs:
[Thu Sep 22 03:21:26] [Location] Clearing LastCDKey for Player Driptin Dasterly

I am looking at the on client enter script and I see there are quite a few delayed commands, deleting local integers (although not this one specifically.) Like this portion of the on client enter script:
 //Remove all uses for usable feats
      if ( GetLocalInt( GetModule( ), sName + "_losefeatsuses" ))
      {
        for( nFeat = 0; nFeat <= MAX_FEATS; ++nFeat )
        {
          if( GetHasFeat( nFeat, oPC ))
          {
            for( i = 0; i <= 20; ++i )
            {
              DecrementRemainingFeatUses( oPC, nFeat );
            }
          }
        }
                //Clean up local variable to free up memory
        DeleteLocalInt( GetModule( ), sName + "_logged" );
        DeleteLocalInt( GetModule( ), sName + "_hp" );
        DeleteLocalInt( GetModule( ), sName + "_losefeatsuses" );
        for ( nSpell = 0; nSpell <= MAX_SPELLS; ++nSpell )
        {
          DeleteLocalInt( GetModule( ), sName + "_Spell_" + IntToString( nSpell ) + "_" );
        }

Could this be causing the problem?
               
               

               


                     Modifié par Lazarus Magni, 22 septembre 2011 - 10:17 .
                     
                  


            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #8 on: September 22, 2011, 09:28:52 pm »


               What you could do, is put the effect creation and application into a subroutine assigned to the wand, then check to see if the player has an effect created by that item instead of using a variable.  It would be slightly less efficient processor wise, but there'd be no chance of the error you're getting now that way.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #9 on: September 22, 2011, 11:13:04 pm »


               Can you elaborate on that concept FB? I am not sure if I am understanding what you are saying. Keep in mind I am not a scripter...
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #10 on: September 22, 2011, 11:41:50 pm »


               

Lazarus Magni wrote...

Can you elaborate on that concept FB? I am not sure if I am understanding what you are saying. Keep in mind I am not a scripter...


Something like this:

// In a seperate routine so the creation of the affects can be applied by the
// creator of choice.
void ApplyDDEffects (object oPC);

// Checks to see if oTarget has an effect created by oCreator
int GetHasEffectByCreator (object oTarget, object oCreator);

void main()
{
 // Include bypassing event activation check.
 if (GetLocalInt(OBJECT_SELF,"X2_L_LAST_ITEM_EVENT") != 0) return;
 // if(!GetUserDefinedItemEventNumber() == X2_ITEM_EVENT_ACTIVATE) return; 

 object oPC = GetItemActivator();
 object oItem = GetItemActivated();

 if (!GetHasFeat(FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE, oPC))
    {
     FloatingTextStringOnCreature ("You have no uses of this feat left.", oPC, FALSE);
     return;
    }
 if (GetHasEffectByCreator (oPC, oItem))
    {
     FloatingTextStringOnCreature("Feat still in cool down.", oPC, FALSE);
     return;
    }

// By moving the effect declarations to an assigned subscript, you can control
// what object creates the effect in order to compare against it later.
AssignCommand (oItem, ApplyDDEffects (oPC));
}

void ApplyDDEffects (object oPC)
{
 PlayVoiceChat(VOICE_CHAT_BATTLECRY1, oPC);
 int nclassLevel = GetLevelByclass(class_TYPE_DWARVENDEFENDER, oPC);
 int nPercent = nclassLevel/10 *5;
 int nHP = (nclassLevel + GetAbilityModifier(ABILITY_CONSTITUTION, oPC)) *10;

 effect eHP = EffectTemporaryHitpoints(nHP);
 effect eVis = EffectVisualEffect(VFX_DUR_AURA_PULSE_RED_YELLOW);
 
 effect eLink = EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, nPercent);
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_DIVINE, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_ELECTRICAL, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_FIRE, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_MAGICAL, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_NEGATIVE, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_PIERCING, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_POSITIVE, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SLASHING, nPercent));
 eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SONIC, nPercent));
 eLink = EffectLinkEffects(eLink, eVis);
 
 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 60.0);
 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHP, oPC, 60.0);
 DecrementRemainingFeatUses(oPC, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE);
}

int GetHasEffectByCreator (object oTarget, object oCreator)
{
 effect eEffect = GetFirstEffect (oTarget);
 while (GetIsEffectValid (eEffect))
    {
     if (GetEffectCreator (eEffect) == oCreator) return TRUE;
     eEffect = GetNextEffect (oTarget);
    }
return FALSE;
}



Whatever object is running the script at the time the effect is created gets stored with the effect. Since it's the module originally running the script, it's better to assign the creation of the effect to an object that won't be making any other effects to check against.

Edited to add the formatting back in.  The "class" alterations you'll have to fix yourself after copying.  It's just something these boards do.
               
               

               


                     Modifié par Failed.Bard, 22 septembre 2011 - 10:46 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #11 on: September 23, 2011, 12:00:47 am »


               Just so I am clear, so this is one script, that would replace the existing one? I am still fairly unfamilar with the scripting vanacular, and in this instance "a seperate routine" is confusing me. By that you just meant an additional routine within the existing script, and not a seperate script correct? Also, not sure what you mean about the formating... Is there something specific in the formating here on the boards that needs to be changed in the actual script?
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #12 on: September 23, 2011, 12:25:48 am »


               The formatting is just for readability.  Aside from it changing "class" to always be small case within the scripts, it's not really a negative change removing it, it's just that little bit harder for others to read through to look at without the indenting and spacings intended.

 These lines will need fixing though:

int nclassLevel = GetLevelByclass(class_TYPE_DWARVENDEFENDER, oPC);
int nPercent = nclassLevel/10 *5;
int nHP = (nclassLevel + GetAbilityModifier(ABILITY_CONSTITUTION, oPC)) *10;

I tried editing them to get class_TYPE_* and nclassLevel to post with the capital letters in "class", but it keeps making them all small case.


 as for the scripts themselves, those three scripts would all go within the items script as a complete replacement for the original, if you wanted to try/use them.

 I'm not really that good at explaining scripts, I might have used the wrong terms.  void main() is the primary script, and under a tag based system will be called on any item event.
 If it's an item activation event, it then checks for the remaining feats, and the new check to see if there's an effect on the user created by the item.  If it passes both those checks, it calls the new sub-routine, which assigns the item as the effect creator to check against the next time the item is used.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #13 on: September 23, 2011, 12:42:11 am »


               Thank you very much FB, for the script, and the clarification/explaination. I really appreciate it. So I take it I don't need the include from the original script?

Edit: Got it to compile. I will test this, and report back my findings.
               
               

               


                     Modifié par Lazarus Magni, 22 septembre 2011 - 11:44 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Could use a lil help with a few scripts.
« Reply #14 on: September 23, 2011, 01:05:40 am »


               Well on initial testing this looks great Failed Bard, thank you so much! It will require some more extensive testing live to be sure, but so far haven't experienced the bug once yet. Thank you again, and thank you also to everyone who offered their input, ideas, and help. Cheers you all! This is a much needed boost for DDs on my mod.