Author Topic: "Reduce speed HASTE" Scripting  (Read 1602 times)

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #15 on: January 24, 2014, 07:33:44 pm »


               Perhaps, but at that point it may just be easier to grant a bonus attack effect for equipping certain items rather than penalizing haste.
               
               

               
            

Legacy_MagicalMaster

  • Hero Member
  • *****
  • Posts: 2712
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #16 on: January 24, 2014, 07:50:55 pm »


               Bonus attack effect doesn't increase spellcasting speed, though, and something like giving Autoquicken III won't make feats cast faster.
               
               

               
            

Legacy_WhiteTiger

  • Hero Member
  • *****
  • Posts: 889
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #17 on: January 24, 2014, 08:07:06 pm »


               I found how do to hide the icon speed penalty...

Messabe by ShaDoOoW

"This function will hide just applied effect's icon. How it works? Simply, I apply this effect twice, first time normally, but second time with some other effect in link. And then I will strip the second linked effect, so effect icon will disappear but original effect will stay."

//nDurationType - only permanent and temporary, its logical
//may not work properly with linked effect, proper testing is recommended
void ApplyEffectToPCAndHideIcon(int nDurationType, effect eEffect, object oPC, float fDuration=0.0);
void ApplyEffectToPCAndHideIcon(int nDurationType, effect eEffect, object oPC, float fDuration=0.0)
{
ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);eEffect = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
RemoveEffect(oPC,eEffect);
}


  to apply (on_player_equip) the speed decrease hide icon (already WhiZard and Squatting Monk way)

//nDurationType - only permanent and temporary, its logical
//may not work properly with linked effect, proper testing is recommended
void ApplyEffectToPCAndHideIcon(int nDurationType, effect eEffect, object oPC, float fDuration=0.0);
void ApplyEffectToPCAndHideIcon(int nDurationType, effect eEffect, object oPC, float fDuration=0.0)
{
ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
eEffect = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
RemoveEffect(oPC,eEffect);
}
void main()
{

object oItem = GetPCItemLastEquipped();

    // If the equipped item has the Haste property... 
  if (GetItemHasItemProperty(oItem, ITEM_PROPERTY_HASTE)) 
  {   
    object oPC = GetPCItemLastEquippedBy(); 
      int nItems = GetLocalInt(oPC, "HastedItems");

        // Slow him if he hasn't been slowed by another hasted item.   
    if (!nItems)     
  {           

    effect eSlow = EffectMovementSpeedIncrease(-25);                    ApplyEffectToPCAndHideIcon(DURATION_TYPE_PERMANENT, eSlow, oPC); 
      }
        // Increment a counter for hasted items in case the PC has more than one   
    SetLocalInt(oPC, "HastedItems", nItems + 1); 
  }


}


Link code social.bioware.com/forum/1/topic/192/index/3174344#3180147 
               
               

               


                     Modifié par sandronejm, 24 janvier 2014 - 08:58 .
                     
                  


            

Legacy_WhiteTiger

  • Hero Member
  • *****
  • Posts: 889
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #18 on: January 24, 2014, 08:44:12 pm »


               

WhiZard says...

The number of scripts needed to get the behavior for the haste item property to work is significant, which may be a reason to stay away from perma-haste items.


What do you mean with this?

Unfortunately the speed penalty does not work when:
1.Player logs out and logs in the game.
2.On respawn (don`t work).
3.Hide/Unhide.
4.On rest (don`t work after finished).
               
               

               


                     Modifié par sandronejm, 24 janvier 2014 - 08:57 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #19 on: January 25, 2014, 04:54:15 am »


               

MagicalMaster wrote...

Bonus attack effect doesn't increase spellcasting speed, though, and something like giving Autoquicken III won't make feats cast faster.


I was not recommending getting away from the spells and abilities that grant haste.  For them, haste can be linked to the movement speed adjustment, so that one won't disappear without the other (although the slow effect will increase its potency against hasted characters).

Item properties of haste can be much more difficult to handle as effects can get lost while properties endure.  For them placing a bonus attack might be better as errors will not suddenly produce exploits.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #20 on: January 25, 2014, 05:13:56 am »


               

sandronejm wrote...

WhiZard says...

The number of scripts needed to get the behavior for the haste item property to work is significant, which may be a reason to stay away from perma-haste items.


What do you mean with this?

Unfortunately the speed penalty does not work when:
1.Player logs out and logs in the game.
2.On respawn (don`t work).
3.Hide/Unhide.
4.On rest (don`t work after finished).


Read the above.  I have done in depth studies in movement speed application and removal. 

Point 3 should work regardless,  as hide/unhide effetively applies and removes a movement speed effect (multiplying speed by 0.5 then recalculating the speed without the 0.5 multiplication).  Haste and 30% movement penalty result in a speed of 1.05 times normal movent (1.5 times 0.7),  with the exception of monk and barbarian who have a bug regarding their bonus being added in every time a new movement speed effect is added.  The only other avenue that could reasonably cause problems is the recursive nature of applying movement speed effects to rebound off the minimum speed cap (of 0.125 base speed) or the maximum cap (of 1.5 base speed) (e.g. 50% increase with a 50% increase and then a 30% deacrease will still net 1.05 base speed as the first increase already reached the cap).  In short I am betting the reason you are saying point three doesn't work, is because the icon for the movement speed disappears, rather than the character failing to be slowed.

Points 2 and 4 were already addressed by MM above.

For point 1 are you looking at a character that has logged off and logged back into the same server session? Or has the server reset in between loggings?
               
               

               
            

Legacy_WhiteTiger

  • Hero Member
  • *****
  • Posts: 889
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #21 on: January 25, 2014, 05:38:50 am »


               Yes, when login/logout - in the same session - the penalty speed is removed. The character back to walk fast.
               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #22 on: January 25, 2014, 09:38:15 pm »


               When a player logs in, the OnAcquireItem and OnPlayerEquipItem events run before even OnClientEnter. It's possible that effects aren't getting applied because the PC is not a fully valid object yet. Try DelayCommand()-ing the application of the slow effect and see if that helps any. If that doesn't work, you can loop through the PC's equipped items OnClientEnter to determine if they have any hasted items equipped and apply the slow effect there.

As others have noted, there's a lot to consider when trying to do this stuff, and it's going to be difficult to make a fool-proof system that isn't full of ugly hacks. A far simpler solution would be to remove perma-haste items from the module.
               
               

               
            

Legacy_WhiteTiger

  • Hero Member
  • *****
  • Posts: 889
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #23 on: January 25, 2014, 10:22:59 pm »


               DelayCommand()-ing what's this?

1.The idea is to create a script to check on login if the player is using a Hasted item and apply the penalty speed.
2.On respawn is the same thing - checks on respawn if the player are using hasted item.
3.Hide/Unhide are OK - working.
4.On rest - checks on rest if the player are using hasted item and apply penalty.

I was testing the script with penalty Increase -75% (really slow moviment). I was fighting with a Red Dragon and a Mage... When I receive a spell damage from enemy I back to run fast (with hasted normal).
This script are very bugged. ):

Squatting Monk, I can't remove all perma-hasted items from the module. Don't we have other way to reduce speed hasted?
               
               

               


                     Modifié par sandronejm, 25 janvier 2014 - 10:24 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #24 on: January 25, 2014, 10:48:03 pm »


               There are ways to do what you want, but they're fairly involved. Here's our sample code for mud that slows players while they're in it:

                /* Shedaklah - Gasping Crater
                 *   Slowing Mud (height 11.5)
                 */
                case 31: {
                    vector vPos = GetPosition(oTarget);
                    if (vPos.z < 11.5 && !GetCanPasswall(oTarget)) {
                        effect eEff = EffectSpellImmunity(HGSPELL_UNUSED);
                        eEff = SupernaturalEffect(eEff);
                        SetEffectSpellId(eEff, HGEFFECT_LETHARGY);

                        if (!GetHasSpellEffect(HGEFFECT_LETHARGY, oTarget))
                            FloatingTextStringOnCreature("The mud sticks to you and slows you down!", oTarget, FALSE);

                        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEff, oTarget, 12.0);
                    }
                }


Basically, we set a spell id on an otherwise unused/non-existant spell immunity effect, creating a new spell id effect. That, in itself, requires nwnx_structs, though you can get around that by using a custom effect creator object and checking something unique, like tag or resref, of GetEffectCreator. 

That's just the start, because, by itself, that effect does nothing, other than serve as a marker.

We have the following scripts in our central include:

int GetAdjustedMovementRate (int nRate, int nAdjust) {
    if (nRate == MOVEMENT_RATE_PC)
        nRate = MOVEMENT_RATE_NORMAL;

    if (nRate == MOVEMENT_RATE_DM_FAST    ||
        nRate == MOVEMENT_RATE_IMMOBILE   ||
        nRate == MOVEMENT_RATE_EXTRA_SLOW ||
        nRate == MOVEMENT_RATE_SUPER_SLOW ||
        nRate == MOVEMENT_RATE_GLACIAL)
        return nRate;

    switch (nRate) {
        case MOVEMENT_RATE_VERY_SLOW:
            nRate = 0;
            break;

        case MOVEMENT_RATE_SLOW:
            nRate = 1;
            break;

        case MOVEMENT_RATE_RELAXED:
            nRate = 2;
            break;

        case MOVEMENT_RATE_FAST:
            nRate = 4;
            break;

        case MOVEMENT_RATE_FASTER:
            nRate = 5;
            break;

        case MOVEMENT_RATE_VERY_FAST:
            nRate = 6;
            break;

        case MOVEMENT_RATE_EXTRA_FAST:
        case MOVEMENT_RATE_SUPER_FAST:
        case MOVEMENT_RATE_HYPER_FAST:
        case MOVEMENT_RATE_LIGHTSPEED:
        case MOVEMENT_RATE_RIDICULOUS:
        case MOVEMENT_RATE_LUDICROUS:
            nRate = 7 + (nRate - MOVEMENT_RATE_EXTRA_FAST);
            break;

        default:
            nRate = 3;
            break;
    }

    nRate += nAdjust;

    if (nRate > 12)
        nRate = 12;
    else if (nRate < 0)
        nRate = 0;

    switch (nRate) {
        case 0:
            nRate = MOVEMENT_RATE_VERY_SLOW;
            break;

        case 1:
            nRate = MOVEMENT_RATE_SLOW;
            break;

        case 2:
            nRate = MOVEMENT_RATE_RELAXED;
            break;

        case 4:
            nRate = MOVEMENT_RATE_FAST;
            break;

        case 5:
            nRate = MOVEMENT_RATE_FASTER;
            break;

        case 6:
            nRate = MOVEMENT_RATE_VERY_FAST;
            break;

        case 7:  /* MOVEMENT_RATE_EXTRA_FAST */
        case 8:  /* MOVEMENT_RATE_SUPER_FAST */
        case 9:  /* MOVEMENT_RATE_HYPER_FAST */
        case 10: /* MOVEMENT_RATE_LIGHTSPEED */
        case 11: /* MOVEMENT_RATE_RIDICULOUS */
        case 12: /* MOVEMENT_RATE_LUDICROUS  */
            nRate = MOVEMENT_RATE_EXTRA_FAST + (nRate - 7);
            break;

        default:
            nRate = MOVEMENT_RATE_NORMAL;
            break;
    }

    return nRate;
}

int GetBaseMovementRate (object oPC) {
    int nRate = GetLocalInt(oPC, "SubraceMovementRate");

    if (GetQuasiclass(oPC) == QUASICLASS_ACCURSED_PARIAH)
        nRate = MOVEMENT_RATE_NORMAL;
    else if (GetLocalInt(oPC, "RDDLevel") >= 30)
        nRate = MOVEMENT_RATE_FAST;

    if (nRate <= 0)
        nRate = MOVEMENT_RATE_NORMAL;

    if (GetLocalInt(oPC, "StatArtifactUsed") == HGARTIFACT_TEAR_OF_SELUNE)
        nRate = GetAdjustedMovementRate(nRate, 2);

    if (GetHasFeat(FEAT_EPIC_BLINDING_SPEED, oPC))
        nRate = GetAdjustedMovementRate(nRate, 1);
    if (GetHasFeat(HGFEAT_Y_QUICKNESS, oPC))
        nRate = GetAdjustedMovementRate(nRate, 1);

    return nRate;
}

void RecalculateMovementRate (object oPC) {
    if (!GetIsPC(oPC) || GetIsDM(oPC))
        return;

    int nRate;

    if (GetHasSpellImmunity(SPELLABILITY_DW_DEFENSIVE_STANCE, oPC)  ||
        GetHasSpellEffect(HGSPELL_VISCID_GLOB, oPC)) {
        nRate = MOVEMENT_RATE_GLACIAL;
    } else if ((GetHasSpellEffect(HGEFFECT_LETHARGY, oPC)  ||
                GetHasSpellEffect(HGEFFECT_GNOMISH_INVENTOR_KD_IMMUNITY, oPC)) &&
                GetLocalInt(oPC, "StatArtifactUsed") != HGARTIFACT_TEAR_OF_SELUNE) {
        nRate = MOVEMENT_RATE_SLOW;
    } else {
        nRate = GetBaseMovementRate(oPC);

        if (GetHasSpellEffect(SPELL_EXPEDITIOUS_RETREAT, oPC) || GetHasSpellEffect(SPELL_FREEDOM_OF_MOVEMENT, oPC))
            nRate = GetAdjustedMovementRate(nRate, GetLocalInt(oPC, "MovementRateBonus"));
    }

    if (nRate == MOVEMENT_RATE_NORMAL)
        nRate = MOVEMENT_RATE_PC;
    SetMovementRate(oPC, nRate);
}


These moverate consts are in nwnx_functions:

const int MOVEMENT_RATE_PC          = 0;
const int MOVEMENT_RATE_IMMOBILE    = 1;
const int MOVEMENT_RATE_VERY_SLOW   = 2;
const int MOVEMENT_RATE_SLOW        = 3;
const int MOVEMENT_RATE_NORMAL      = 4;
const int MOVEMENT_RATE_FAST        = 5;
const int MOVEMENT_RATE_VERY_FAST   = 6;
const int MOVEMENT_RATE_DEFAULT     = 7;
const int MOVEMENT_RATE_DM_FAST     = 8;
const int MOVEMENT_RATE_FASTER      = 9;
const int MOVEMENT_RATE_EXTRA_FAST  = 10;
const int MOVEMENT_RATE_SUPER_FAST  = 11;
const int MOVEMENT_RATE_HYPER_FAST  = 12;
const int MOVEMENT_RATE_LIGHTSPEED  = 13;
const int MOVEMENT_RATE_RIDICULOUS  = 14;
const int MOVEMENT_RATE_LUDICROUS   = 15;
const int MOVEMENT_RATE_RELAXED     = 16;
const int MOVEMENT_RATE_EXTRA_SLOW  = 17;
const int MOVEMENT_RATE_SUPER_SLOW  = 18;
const int MOVEMENT_RATE_GLACIAL     = 19;


We simply recalc the movement rate for the pc at certain places in the mod:

fky_deathprocess (56):     RecalculateMovementRate(oPC);
fky_restprocess (264):     RecalculateMovementRate(oPC);
hgs_viscidglob (64):                 RecalculateMovementRate(si.target);
hg_inc (3661): void RecalculateMovementRate (object oPC) {
hg_mod_heartbeat (36):             RecalculateMovementRate(oPC);
nw_s0_freemove (107):         DelayCommand(0.5, RecalculateMovementRate(si.target));
qc_gi_inc (642):                 DelayCommand(0.1, RecalculateMovementRate(oTarget));
x0_s0_shield (47):     DelayCommand(0.1, RecalculateMovementRate(si.caster));


fky_deathprocess is called whenever a pc is brought back to life. It's essentially a 'rez event', and you'll need one to do this. fky_restprocess is the same, though that's a convenience script, because we sometimes call it other than when a pc rests (ForceRests, among other things):

ag_wandering_mon (92):         ExecuteScript("fky_restprocess", oPC);
asmoset001 (26):             ExecuteScript("fky_restprocess", oPC);
biorejuvenator (20):         ExecuteScript("fky_restprocess", oPC);
fky_chat_dm_comm (1140):                             if ((!VerifyDMKey(oDMTarget)) && (!VerifyAdminKey(oDMTarget)) || (oDMTarget == oDMPC)) {ForceRest(oDMTarget); ExecuteScript("fky_restprocess", oDMTarget);}
hellhiduse (105):     ExecuteScript("fky_restprocess", oPC);
hgll_start_dlg (9): - old altar had forced rest and fky_restprocess onenter, omitted from this setup,
hg_inc (4302):     ExecuteScript("fky_restprocess", oPC);
legendaltarlimit (14):         ExecuteScript("fky_restprocess", oPC);
paragon_spell (1477):     /* counter spell, recalc done each rest in fky_restprocess */


Firing RecalculateMovementRate in the module heartbeat, by the way, also prevents a known speed exp%lo@it. The loop is straightfoward enough:

void main() {
    object oMod = GetModule();
    object oMes = GetMessenger();
    int nUptime = GetLocalInt(oMod, "uptime");
    int nMemory = GetProcessMemoryUsage();
    int nMessages = 0, nPlayers = 0;
    string sServer = GetLocalString(oMod, "ServerNumber");
    string sBootTime = IntToString(GetLocalInt(oMod, "boottime"));

    {
        object oPC;

        for (oPC = GetFirstPC(); GetIsObjectValid(oPC); oPC = GetNextPC()) {
            nPlayers++;
            RecalculateMovementRate(oPC);
            RecalculateDexModifier(oPC);

            int nAlarm = GetLocalInt(oPC, "AlarmUptime");
            if (nAlarm > 0 && nAlarm <= nUptime) {
                DeleteLocalInt(oPC, "AlarmUptime");
                SendChatLogMessage(oPC, C_PINK + "[Alarm] " + GetLocalString(oPC, "AlarmMessage") + C_END, oMes, 4);
            }
        }

        SetLocalInt(oMod, "ServerPlayers", nPlayers);
    }


All of this relies on SetMovementRate, which can be found in both nwnx_funcs and nwnx_functions (pretty sure the functinos one is deprecated, though).

Like I said, involved, but there's no simpler way that actually works in all cases.

Funky
               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #25 on: January 25, 2014, 11:07:38 pm »


               

sandronejm wrote...

DelayCommand()-ing what's this?

DelayCommand().
               
               

               
            

Legacy_WhiteTiger

  • Hero Member
  • *****
  • Posts: 889
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #26 on: January 26, 2014, 02:36:14 am »


               1. Thanks Squatting Monk, i'll read about. 

2. Funky, I like, what's steps to use this system?
               
               

               


                     Modifié par sandronejm, 26 janvier 2014 - 02:38 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
"Reduce speed HASTE" Scripting
« Reply #27 on: January 26, 2014, 03:57:33 am »


               That's covered on the NWNX boards. A lot depends on what kind of server you're running. You can find both instructions on installation, and a helpful community, at the site and forum:
NWNX site, with a link to the forum

Funky