"Reduce speed HASTE" Scripting
#1
Posté 23 janvier 2014 - 12:53
if anyone can help i'll be grateful.
#2
Posté 23 janvier 2014 - 03:04
If it is movement speed in general, you can decrease the values in creaturespeed.2da.
If the problem is haste, and you aren't using perma-haste gear you can add on a movement speed penalty to the abilities that produce it.
#3
Posté 24 janvier 2014 - 12:35
I found it:
--------------------------------------------------------------------------------------
Message by Squatting Monk -
You can reduce the movement speed with EffectMovementSpeedDecrease().
Add this right under line 59 of nw_s0_haste:
Code:
// Slow it down a bit
eHaste = EffectLinkEffects(EffectMovementSpeedDecrease(30), eHaste);
Replace 30 with a smaller value if that slows it down too much.
Note: this will not help with hasted items, only the spell.
----------------------------------------------------------------------------------------------
Modifié par sandronejm, 26 janvier 2014 - 01:54 .
#4
Posté 24 janvier 2014 - 12:45
#5
Posté 24 janvier 2014 - 12:47
#6
Posté 24 janvier 2014 - 01:23
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 = EffectMovementSpeedDecrease(30);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSlow, oPC);
}
// Increment a counter for hasted items in case the PC has more than one
SetLocalInt(oPC, "HastedItems", nItems + 1);
}
...and something like this in your OnPlayerUnEquipItem script:
object oItem = GetPCItemLastUnequipped();
// If the unequipped item has the Haste property...
if (GetItemHasItemProperty(oItem, ITEM_PROPERTY_HASTE))
{
object oPC = GetPCItemLastUnequippedBy();
int nItems = GetLocalInt(oPC, "HastedItems");
// Remove the slow effect if he has no more hasted items.
if (nItems == 1)
{
object oCreator = GetModule();
effect eEffect = GetFirstEffect(oPC);
while (GetIsEffectValid(eEffect))
{
if (GetEffectType(eEffect) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE &&
GetEffectCreator(eEffect) == oCreator) // Don't remove slow effects from other sources
RemoveEffect(oPC, eEffect);
eEffect = GetNextEffect(oPC);
}
}
// Decrement a counter for hasted items in case the PC has more than one
SetLocalInt(oPC, "HastedItems", nItems - 1);
}Note: I'm not sure if equipped items that are destroyed with DestroyObject() are still valid when the OnPlayerUnequipItem event is fired. If not, you'd need to loop through all currently equipped items to see if a now-invalid item had the Haste property.
Modifié par Squatting Monk, 24 janvier 2014 - 02:54 .
#7
Posté 24 janvier 2014 - 02:24
The ON_PLAYER_EQUIP has compiled with sucess but the
on_player_UNEQUIP don't compile (looks 8 line wrong)
#8
Posté 24 janvier 2014 - 02:54
object oPC = GetPCItemLastUnquippedBy();
...should read:
object oPC = GetPCItemLastUnequippedBy();
Modifié par Squatting Monk, 24 janvier 2014 - 02:55 .
#9
Posté 24 janvier 2014 - 03:06
#10
Posté 24 janvier 2014 - 04:23
effect eSlow = EffectMovementSpeedDecrease(30);
with
effect eSlow = EffectMovmentSpeedIncrease(-30);
and for OnUnEquip replace
if (GetEffectType(eEffect) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE && GetEffectCreator(eEffect) == oCreator)
with
if (GetEffectType(eEffect) == EFFECT_TYPE_MOVEMENT_SPEED_INCREASE && GetEffectCreator(eEffect) == oCreator)
Can't have those with freedom getting an unnecessary advantage can we?
#11
Posté 24 janvier 2014 - 05:19
I spent some time testing the system and it's work fine. It's only works on equip. When player login with item already equiped the penalty speed isn't as we programmed ):
#12
Posté 24 janvier 2014 - 04:35
The code effect eSlow = EffectMovmentSpeedIncrease(-30); won't compile. You need replace Movment to Movement.
1. Rogues hide/unhide cancel the speed decrease.
2. Login in the game cancell the speed decrease.
3. I'm not sure but rest cancel the speed decrease.
#13
Posté 24 janvier 2014 - 05:10
#14
Posté 24 janvier 2014 - 06:28
2. Login may have the same issue as 1). Check to see if you are just missing the icon or the effect itself.
3. As MM described an effect needs to be supernatural to not be removed on rest.
Additionally there may be issues with dying and resurrection (so that a character, if resurrected with the haste item already equipped, will not incur a penalty). 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.
Modifié par WhiZard, 24 janvier 2014 - 06:42 .
#15
Posté 24 janvier 2014 - 07:09
#16
Posté 24 janvier 2014 - 07:33
#17
Posté 24 janvier 2014 - 07:50
#18
Posté 24 janvier 2014 - 08:07
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 .
#19
Posté 24 janvier 2014 - 08:44
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 .
#20
Posté 25 janvier 2014 - 04:54
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.
#21
Posté 25 janvier 2014 - 05:13
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?
#22
Posté 25 janvier 2014 - 05:38
#23
Posté 25 janvier 2014 - 09:38
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.
#24
Posté 25 janvier 2014 - 10:22
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 .
#25
Posté 25 janvier 2014 - 10:48
/* 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





Retour en haut







