From 92e0fb145ffa3a76d405a9ae701dea241ff1877b Mon Sep 17 00:00:00 2001 From: Pyrdacor Date: Thu, 3 Dec 2020 16:07:21 +0100 Subject: [PATCH] Sleep is removed when getting damage, battle-only ailments are removed after battle, curse spell animations look now better, skip battle actions when being disabled during round, corrected damage for fire spells --- Ambermoon.Core/Battle.cs | 43 +++++++++++++++---- Ambermoon.Core/Game.cs | 8 +++- Ambermoon.Core/Render/SpellAnimation.cs | 15 ++++--- Ambermoon.Data.Common/Enumerations/Ailment.cs | 6 +++ 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/Ambermoon.Core/Battle.cs b/Ambermoon.Core/Battle.cs index 39f514cc..34f131f8 100644 --- a/Ambermoon.Core/Battle.cs +++ b/Ambermoon.Core/Battle.cs @@ -1236,6 +1236,8 @@ void HurtAnimationFinished() PlayBattleEffectAnimation(BattleEffect.HurtMonster, tile, battleTicks, EndHurt); } + if (target.Ailments.HasFlag(Ailment.Sleep)) + RemoveAilment(Ailment.Sleep, target); target.Damage(damage); return; } @@ -1318,6 +1320,19 @@ void ShowFailMessage(string message) return true; } + void RemoveAilment(Ailment ailment, Character target) + { + // Healing spells or potions. + // Sleep can be removed by attacking as well. + target.Ailments &= ~ailment; + + if (target is PartyMember partyMember) + { + game.UpdateBattleStatus(partyMember); + layout.UpdateCharacterNameColors(game.CurrentSavegame.ActivePartyMemberSlot); + } + } + void AddAilment(Ailment ailment, Character target) { target.Ailments |= ailment; @@ -1327,6 +1342,12 @@ void AddAilment(Ailment ailment, Character target) game.UpdateBattleStatus(partyMember); layout.UpdateCharacterNameColors(game.CurrentSavegame.ActivePartyMemberSlot); } + + if (!ailment.CanSelect()) // disabled + { + foreach (var action in roundBattleActions.Where(a => a.Character == target)) + action.Skip = true; + } } static float GetMonsterDeathScale(Monster monster) @@ -1407,21 +1428,24 @@ void ApplySpellEffect(Character caster, Character target, Spell spell, uint tick case Spell.Drug: AddAilment(Ailment.Drugged, target); break; - case Spell.GhostWeapon: - DealDamage(25, 10); // TODO - return; case Spell.Firebeam: - DealDamage(25, 10); // TODO + // seen 21-29 (assume 20-30) + DealDamage(20, 10); // TODO return; case Spell.Fireball: - DealDamage(45, 10); // TODO + // seen 41-80 (assume 40-80) + DealDamage(40, 40); // TODO return; case Spell.Firestorm: - DealDamage(60, 10); // TODO + // seen 35-63 (assume 35-65) + DealDamage(35, 30); // TODO return; case Spell.Firepillar: - DealDamage(80, 10); // TODO + // seen 41-69 (assume 40-70) + DealDamage(40, 30); // TODO return; + // Winddevil: seen 10-15 + // Windhowler: seen 35-46 default: // TODO break; @@ -1455,6 +1479,8 @@ void EndHurt() game.ShowPlayerDamage(game.SlotFromPartyMember(partyMember).Value, Math.Min(damage, partyMember.HitPoints.TotalCurrentValue)); } + if (target.Ailments.HasFlag(Ailment.Sleep)) + RemoveAilment(Ailment.Sleep, target); target.Damage(damage); EndHurt(); } @@ -2255,8 +2281,9 @@ int CalculatePhysicalDamage(Character attacker, Character target) uint CalculateSpellDamage(Character caster, Character target, uint baseDamage, uint variableDamage) { // TODO: how is magic damage calculated? + // TODO: does INT affect damage? // Note: In contrast to physical attacks this should always deal at least 1 damage - return baseDamage; // TODO + return baseDamage + (uint)game.RandomInt(0, (int)variableDamage); // TODO } } diff --git a/Ambermoon.Core/Game.cs b/Ambermoon.Core/Game.cs index c1deb10b..c7ffd03b 100644 --- a/Ambermoon.Core/Game.cs +++ b/Ambermoon.Core/Game.cs @@ -3160,6 +3160,13 @@ void ShowBattleWindow(Event nextEvent, bool surpriseAttack) } void EndBattle(BattleEndInfo battleEndInfo) { + for (int i = 0; i < MaxPartyMembers; ++i) + { + var partyMember = GetPartyMember(i); + + partyMember.Ailments = partyMember.Ailments.WithoutBattleOnlyAilments(); + } + UpdateBattleStatus(); currentBattleInfo.EndBattle(battleEndInfo); currentBattleInfo = null; if (nextEvent != null) @@ -3168,7 +3175,6 @@ void EndBattle(BattleEndInfo battleEndInfo) nextEvent.ExecuteEvent(Map, this, EventTrigger.Always, (uint)RenderPlayer.Position.X, (uint)RenderPlayer.Position.Y, CurrentTicks, ref lastStatus, out bool aborted); } - // TODO: Remove battle-only ailments like sleep and irritation } if (battleEndInfo.MonstersDefeated) { diff --git a/Ambermoon.Core/Render/SpellAnimation.cs b/Ambermoon.Core/Render/SpellAnimation.cs index 5c44059f..31bdc04f 100644 --- a/Ambermoon.Core/Render/SpellAnimation.cs +++ b/Ambermoon.Core/Render/SpellAnimation.cs @@ -524,13 +524,18 @@ void PlayCurse(CombatGraphicIndex iconGraphicIndex) var targetPosition = GetTargetPosition(tile) - new Position(0, Util.Round(8 * scale)); game.AddTimedEvent(TimeSpan.FromMilliseconds(500), () => { - void AddCurseAnimation(CombatGraphicIndex graphicIndex, bool finish) + byte displayLayer = (byte)(fromMonster ? 255 : ((tile / 6) * 60 + 59)); + void AddCurseAnimation(CombatGraphicIndex graphicIndex, Action finishAction, bool reverse) { - AddAnimation(graphicIndex, 1, targetPosition, targetPosition, Game.TicksPerSecond * 3 / 4, - 0.0f, scale, (byte)((tile / 6) * 60 + 59), finish ? (Action)null : () => { }); + AddAnimation(graphicIndex, 1, targetPosition, targetPosition, reverse ? Game.TicksPerSecond / 4 : Game.TicksPerSecond / 2, + reverse ? scale : 0.0f, reverse ? 0.5f * scale : scale, displayLayer, finishAction); } - AddCurseAnimation(CombatGraphicIndex.RedRing, false); - AddCurseAnimation(iconGraphicIndex, true); + AddCurseAnimation(CombatGraphicIndex.RedRing, () => { }, false); + AddCurseAnimation(iconGraphicIndex, () => + { + AddCurseAnimation(CombatGraphicIndex.RedRing, () => { }, true); + AddCurseAnimation(iconGraphicIndex, null, true); // This will trigger the outer finish action + }, false); }); } diff --git a/Ambermoon.Data.Common/Enumerations/Ailment.cs b/Ambermoon.Data.Common/Enumerations/Ailment.cs index 1aef5ab1..0738e5c3 100644 --- a/Ambermoon.Data.Common/Enumerations/Ailment.cs +++ b/Ambermoon.Data.Common/Enumerations/Ailment.cs @@ -28,6 +28,12 @@ public enum Ailment [EditorBrowsable(EditorBrowsableState.Never)] public static class AilmentExtensions { + public static Ailment WithoutBattleOnlyAilments(this Ailment ailments) + { + // TODO: Is madness also battle-only? + return (Ailment)((int)ailments & 0xfff2); + } + public static bool CanFight(this Ailment ailment) { return