From 3db8719ee28ff29f18c6b0e5dee954b59ccc3b36 Mon Sep 17 00:00:00 2001 From: Avenger Date: Sun, 5 Sep 2010 21:07:34 +0200 Subject: [PATCH] improved turning/panic --- gemrb/core/GameScript/Actions.cpp | 3 +- gemrb/core/Scriptable/Actor.cpp | 118 +++++++++++++++++++++++++++----- gemrb/core/Scriptable/Actor.h | 10 ++- gemrb/override/bg1/effects.ids | 1 - gemrb/override/bg2/effects.ids | 1 - gemrb/override/how/effects.ids | 1 - gemrb/override/iwd/effects.ids | 3 +- gemrb/override/shared/panic.spl | Bin 0 -> 346 bytes gemrb/override/shared/turn.spl | Bin 202 -> 202 bytes gemrb/plugins/IWDOpcodes/IWDOpcodes.cpp | 8 +-- 10 files changed, 115 insertions(+), 30 deletions(-) create mode 100644 gemrb/override/shared/panic.spl diff --git a/gemrb/core/GameScript/Actions.cpp b/gemrb/core/GameScript/Actions.cpp index 350462e7e..15706a022 100644 --- a/gemrb/core/GameScript/Actions.cpp +++ b/gemrb/core/GameScript/Actions.cpp @@ -4764,6 +4764,7 @@ void GameScript::Berserk(Scriptable* Sender, Action* /*parameters*/) } Actor *act = (Actor *) Sender; act->SetBaseBit(IE_STATE_ID, STATE_BERSERK, true); + act->Panic(NULL, PANIC_BERSERK); } void GameScript::Panic(Scriptable* Sender, Action* /*parameters*/) @@ -4772,7 +4773,7 @@ void GameScript::Panic(Scriptable* Sender, Action* /*parameters*/) return; } Actor *act = (Actor *) Sender; - act->Panic(); + act->Panic(NULL, PANIC_RANDOMWALK); } /* as of now: removes panic and berserk */ diff --git a/gemrb/core/Scriptable/Actor.cpp b/gemrb/core/Scriptable/Actor.cpp index 2bdf731cb..5baf226f5 100644 --- a/gemrb/core/Scriptable/Actor.cpp +++ b/gemrb/core/Scriptable/Actor.cpp @@ -344,6 +344,8 @@ Actor::Actor() attackProjectile = NULL; lastInit = 0; roundTime = 0; + modalTime = 0; + panicMode = PANIC_NONE; lastattack = 0; inventory.SetInventoryType(INVENTORY_CREATURE); @@ -740,7 +742,8 @@ void Actor::ApplyClab(const char *clab, ieDword max, bool remove) void pcf_morale (Actor *actor, ieDword /*oldValue*/, ieDword /*newValue*/) { if ((actor->Modified[IE_MORALE]<=actor->Modified[IE_MORALEBREAK]) && (actor->Modified[IE_MORALEBREAK] != 0) ) { - actor->Panic(); + //TODO: current attacker should be passed instead of NULL + actor->Panic(NULL, core->Roll(1,3,0) ); } //for new colour actor->SetCircleSize(); @@ -2504,15 +2507,50 @@ void Actor::SelectActor() DisplayStringCore(this, VB_SELECT, DS_CONSOLE|DS_CONST ); } -void Actor::Panic() +void Actor::Panic(Scriptable *attacker, int panicmode) { if (GetStat(IE_STATE_ID)&STATE_PANIC) { + printf("Already paniced\n"); //already in panic return; } if (InParty) core->GetGame()->SelectActor(this, false, SELECT_NORMAL); SetBaseBit(IE_STATE_ID, STATE_PANIC, true); DisplayStringCore(this, VB_PANIC, DS_CONSOLE|DS_CONST ); + + Action *action; + char Tmp[40]; + //FIXME: GenerateActionDirect should work on any scriptable + //they just need global ID + if (panicmode == PANIC_RUNAWAY && !attacker || attacker->Type!=ST_ACTOR) { + panicmode = PANIC_RANDOMWALK; + } + + switch(panicmode) { + case PANIC_RUNAWAY: + strncpy(Tmp,"RunAwayFromNoInterrupt([-1])", sizeof(Tmp) ); + action = GenerateActionDirect(Tmp, (Actor *) attacker); + break; + case PANIC_RANDOMWALK: + strncpy(Tmp,"RandomWalk()", sizeof(Tmp) ); + action = GenerateAction( Tmp ); + break; + case PANIC_BERSERK: + if (Modified[IE_EA]Type==ST_ACTOR) && GameScript::ID_Alignment((Actor *)cleric,AL_EVIL) ) { + evilcleric = true; + } + + //a little adjustment of the level to get a slight randomness on who is turned + unsigned int level = GetXPLevel(true)-(GetGlobalID()&3); + + //this is safely hardcoded i guess + if (Modified[IE_GENERAL]!=GEN_UNDEAD) { + level = GetPaladinLevel(); + if (evilcleric && level) { + LastTurner = cleric->GetGlobalID(); + if (turnlevel >= level+TURN_DEATH_LVL_MOD) { + if (gamedata->Exists("panic", IE_SPL_CLASS_ID)) { + core->ApplySpell("panic", this, cleric, 0); + } else { + printf("Panic from turning!\n"); + Panic(cleric, PANIC_RUNAWAY); + } + } + } + return; + } + //determine alignment (if equals, then no turning) LastTurner = cleric->GetGlobalID(); //determine panic or destruction/control //we get the modified level - if (turnlevel - TURN_DEATH_LVL_MOD >= GetXPLevel(true)) { - if (cleric->Type == ST_ACTOR && ((Actor*)cleric)->MatchesAlignmentMask(AL_EVIL)) { - Effect *fx = fxqueue.CreateEffect(control_undead_ref, GEN_UNDEAD, 3, FX_DURATION_INSTANT_LIMITED); - fx->Duration = core->Time.round_sec; - fx->Target = FX_TARGET_PRESET; - core->ApplyEffect(fx, this, cleric); - delete fx; - } else { - Die(cleric); + if (turnlevel >= level+TURN_DEATH_LVL_MOD) { + if (evilcleric) { + Effect *fx = fxqueue.CreateEffect(control_creature_ref, GEN_UNDEAD, 3, FX_DURATION_INSTANT_LIMITED); + if (!fx) { + fx = fxqueue.CreateEffect(control_undead_ref, GEN_UNDEAD, 3, FX_DURATION_INSTANT_LIMITED); + } + if (fx) { + fx->Duration = core->Time.round_sec; + fx->Target = FX_TARGET_PRESET; + core->ApplyEffect(fx, this, cleric); + delete fx; + return; + } + //fallthrough for bg1 } - } else if (turnlevel - TURN_PANIC_LVL_MOD >= GetXPLevel(true)) { - Panic(); + Die(cleric); + } else if (turnlevel >= level+TURN_PANIC_LVL_MOD) { + printf("Panic from turning!\n"); + Panic(cleric, PANIC_RUNAWAY); } } @@ -3191,7 +3260,7 @@ void Actor::Die(Scriptable *killer) } else if (Modified[IE_CLASS] == CLASS_FLAMINGFIST) { repmod = core->GetReputationMod(3); } - if (MatchesAlignmentMask(AL_EVIL)) { + if (GameScript::ID_Alignment(this,AL_EVIL) ) { repmod += core->GetReputationMod(7); } if (repmod) { @@ -4541,8 +4610,17 @@ void Actor::ModifyDamage(Actor *target, Scriptable *hitter, int &damage, int &re } void Actor::UpdateActorState(ieDword gameTime) { + if (ModalState == MS_NONE) { + return; + } + if (modalTime==gameTime) { + return; + } + //apply the modal effect on the beginning of each round - if (((gameTime-roundTime)%core->Time.round_size==0) && ModalState) { + if ((((gameTime-roundTime)%core->Time.round_size)==0)) { + //we can set this to 0 + modalTime = gameTime; if (!ModalSpell[0]) { printMessage("Actor","Modal Spell Effect was not set!\n", YELLOW); ModalSpell[0]='*'; @@ -6548,6 +6626,7 @@ bool Actor::TryToHide() { } // only works with masks; use direct comparison for specific alignment checks +/* not needed, use GameScript::ID_Alignment bool Actor::MatchesAlignmentMask(ieDword mask) { ieDword stat = Modified[IE_ALIGNMENT]; @@ -6572,6 +6651,7 @@ bool Actor::MatchesAlignmentMask(ieDword mask) } } +*/ bool Actor::InvalidSpellTarget() { diff --git a/gemrb/core/Scriptable/Actor.h b/gemrb/core/Scriptable/Actor.h index 682693536..1c0d0fc78 100644 --- a/gemrb/core/Scriptable/Actor.h +++ b/gemrb/core/Scriptable/Actor.h @@ -77,6 +77,12 @@ struct PolymorphCache; #define GD_CHECK 1 #define GD_FEEDBACK 2 //(also check) +//Panic modes +#define PANIC_NONE 0 +#define PANIC_BERSERK 1 +#define PANIC_RUNAWAY 2 +#define PANIC_RANDOMWALK 3 + /** flags for GetActor */ //default action #define GA_DEFAULT 0 @@ -283,6 +289,8 @@ public: vvcVector vvcShields; ieDword *projectileImmunity; //classic bitfield ieDword roundTime; //these are timers for attack rounds + ieDword modalTime; //last time the modal effect used + ieDword panicMode; //runaway, berserk or randomwalk ieDword lastInit; bool no_more_steps; int speed; @@ -431,7 +439,7 @@ public: /* call this on gui selects */ void SelectActor(); /* sets the actor in panic (turn/morale break) */ - void Panic(); + void Panic(Scriptable *attacker, int panicmode); /* sets a multi class flag (actually this is a lot of else too) */ void SetMCFlag(ieDword bitmask, int op); /* inlined dialogue start */ diff --git a/gemrb/override/bg1/effects.ids b/gemrb/override/bg1/effects.ids index b8ac88740..d90f00c75 100644 --- a/gemrb/override/bg1/effects.ids +++ b/gemrb/override/bg1/effects.ids @@ -317,4 +317,3 @@ IDS 0x13b AvatarRemovalModifier 0x13c MagicalRest 0x13d State:Haste2 -425 ControlUndead2 diff --git a/gemrb/override/bg2/effects.ids b/gemrb/override/bg2/effects.ids index b3bc49ec7..a78469071 100644 --- a/gemrb/override/bg2/effects.ids +++ b/gemrb/override/bg2/effects.ids @@ -317,4 +317,3 @@ IDS 0x13b AvatarRemovalModifier 0x13c MagicalRest 0x13d State:Haste2 -425 ControlUndead2 diff --git a/gemrb/override/how/effects.ids b/gemrb/override/how/effects.ids index 28a74284e..0eba5c5f7 100644 --- a/gemrb/override/how/effects.ids +++ b/gemrb/override/how/effects.ids @@ -299,4 +299,3 @@ IDS 0x129 HideInShadowsModifier 0x12a UseMagicDeviceModifier 399 AlterAnimation -425 ControlUndead2 diff --git a/gemrb/override/iwd/effects.ids b/gemrb/override/iwd/effects.ids index 374bcd9f4..f4abc7a5f 100644 --- a/gemrb/override/iwd/effects.ids +++ b/gemrb/override/iwd/effects.ids @@ -262,7 +262,7 @@ IDS 0x104 AvatarRemoval 0x105 Protection:Opcode2 0x106 SummonPomab -0x107 ControlUndead +0x107 ControlCreature 0x108 StaticCharge 0x109 CloakOfFear 0x10a MovementRateModifier3 @@ -298,4 +298,3 @@ IDS 0x128 ModifyGlobalVariable 0x129 HideInShadowsModifier 0x12a UseMagicDeviceModifier -425 ControlUndead2 diff --git a/gemrb/override/shared/panic.spl b/gemrb/override/shared/panic.spl new file mode 100644 index 0000000000000000000000000000000000000000..e875f92f1b3524c7070b5235b7c46cb6ceb518a6 GIT binary patch literal 346 zcwP$*@KFdeR8U|5g8FGQ7>EUoc;wK{DPjPrpM^ywrYS6NRxbk+nz|GW)yQBS7WIzK cA@K%g*wsrQsb^piVIX9FA5^^xm?W$o0L79Er~m)} literal 0 HcwPel00001 diff --git a/gemrb/override/shared/turn.spl b/gemrb/override/shared/turn.spl index d72a46e991cb76304b4f69b5e6f90947cf4c9a1f..2dafb19a36ad668a140113c91e3bd2f0fd6cb24f 100644 GIT binary patch delta 11 TcwRfjc#3ht48|)HXBq+k9nb{t delta 11 ScwRfjc#3ht492*LGYtV7_ylOpcode); target->Damage(fx->Parameter1, DAMAGE_COLD, Owner); if (STAT_GET(IE_GENERAL)==GEN_UNDEAD) { - target->Panic(); + target->Panic(Owner, PANIC_RUNAWAY); } return FX_NOT_APPLIED; } @@ -1841,8 +1841,8 @@ int fx_turn_undead2 (Scriptable* Owner, Actor* target, Effect* fx) switch (fx->Parameter2) { case 0: //command - target->Panic(); target->LastTurner = Owner->GetGlobalID(); + target->Panic(Owner, PANIC_RUNAWAY); break; case 1://rebuke if (target->SetSpellState(SS_REBUKED)) { @@ -1852,12 +1852,12 @@ int fx_turn_undead2 (Scriptable* Owner, Actor* target, Effect* fx) target->LastTurner = Owner->GetGlobalID(); break; case 2://destroy - target->Die(Owner); target->LastTurner = Owner->GetGlobalID(); + target->Die(Owner); break; case 3://panic - target->Panic(); target->LastTurner = Owner->GetGlobalID(); + target->Panic(Owner, PANIC_RUNAWAY); break; default://depends on caster if (fx->Parameter1) { -- 2.11.4.GIT