From 94c052dfefee9eaca0aa2f46adc9de8b6b383c9c Mon Sep 17 00:00:00 2001
From: Alexei Kotov <alexdobrohotov@yandex.ru>
Date: Wed, 27 Dec 2023 01:50:30 +0300
Subject: [PATCH] Classify the damage passed to Class::onHit

---
 apps/openmw/mwbase/luamanager.hpp            |  3 ++-
 apps/openmw/mwclass/creature.cpp             |  9 ++++++---
 apps/openmw/mwclass/creature.hpp             |  3 ++-
 apps/openmw/mwclass/npc.cpp                  |  8 +++++---
 apps/openmw/mwclass/npc.hpp                  |  3 ++-
 apps/openmw/mwmechanics/combat.cpp           |  6 ++++--
 apps/openmw/mwmechanics/damagesourcetype.hpp | 15 +++++++++++++++
 apps/openmw/mwmechanics/spelleffects.cpp     |  3 ++-
 apps/openmw/mwworld/class.cpp                |  2 +-
 apps/openmw/mwworld/class.hpp                |  9 ++++++---
 10 files changed, 45 insertions(+), 16 deletions(-)
 create mode 100644 apps/openmw/mwmechanics/damagesourcetype.hpp

diff --git a/apps/openmw/mwbase/luamanager.hpp b/apps/openmw/mwbase/luamanager.hpp
index e4b16ff725..6db85d77ca 100644
--- a/apps/openmw/mwbase/luamanager.hpp
+++ b/apps/openmw/mwbase/luamanager.hpp
@@ -61,7 +61,8 @@ namespace MWBase
 
         // TODO: notify LuaManager about other events
         // virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object,
-        //                          const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) = 0;
+        //                          const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful,
+        //                          DamageSourceType sourceType) = 0;
 
         struct InputEvent
         {
diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp
index 8b80b9336b..cbf5a3d63d 100644
--- a/apps/openmw/mwclass/creature.cpp
+++ b/apps/openmw/mwclass/creature.cpp
@@ -284,7 +284,8 @@ namespace MWClass
 
         if (!success)
         {
-            victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, osg::Vec3f(), false);
+            victim.getClass().onHit(
+                victim, 0.0f, false, MWWorld::Ptr(), ptr, osg::Vec3f(), false, MWMechanics::DamageSourceType::Melee);
             MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
             return;
         }
@@ -345,11 +346,13 @@ namespace MWClass
 
         MWMechanics::diseaseContact(victim, ptr);
 
-        victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true);
+        victim.getClass().onHit(
+            victim, damage, healthdmg, weapon, ptr, hitPosition, true, MWMechanics::DamageSourceType::Melee);
     }
 
     void Creature::onHit(const MWWorld::Ptr& ptr, float damage, bool ishealth, const MWWorld::Ptr& object,
-        const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const
+        const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful,
+        const MWMechanics::DamageSourceType sourceType) const
     {
         MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
 
diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp
index bd7101e93d..b407852242 100644
--- a/apps/openmw/mwclass/creature.hpp
+++ b/apps/openmw/mwclass/creature.hpp
@@ -67,7 +67,8 @@ namespace MWClass
             const osg::Vec3f& hitPosition, bool success) const override;
 
         void onHit(const MWWorld::Ptr& ptr, float damage, bool ishealth, const MWWorld::Ptr& object,
-            const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const override;
+            const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful,
+            const MWMechanics::DamageSourceType sourceType) const override;
 
         std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
         ///< Generate action for activation
diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp
index 0295d3600f..df074ec8bf 100644
--- a/apps/openmw/mwclass/npc.cpp
+++ b/apps/openmw/mwclass/npc.cpp
@@ -599,7 +599,8 @@ namespace MWClass
         float damage = 0.0f;
         if (!success)
         {
-            othercls.onHit(victim, damage, false, weapon, ptr, osg::Vec3f(), false);
+            othercls.onHit(
+                victim, damage, false, weapon, ptr, osg::Vec3f(), false, MWMechanics::DamageSourceType::Melee);
             MWMechanics::reduceWeaponCondition(damage, false, weapon, ptr);
             MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage);
             return;
@@ -672,11 +673,12 @@ namespace MWClass
 
         MWMechanics::diseaseContact(victim, ptr);
 
-        othercls.onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true);
+        othercls.onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true, MWMechanics::DamageSourceType::Melee);
     }
 
     void Npc::onHit(const MWWorld::Ptr& ptr, float damage, bool ishealth, const MWWorld::Ptr& object,
-        const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const
+        const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful,
+        const MWMechanics::DamageSourceType sourceType) const
     {
         MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
         MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp
index eb8cafc9d1..ca0d0ac95d 100644
--- a/apps/openmw/mwclass/npc.hpp
+++ b/apps/openmw/mwclass/npc.hpp
@@ -82,7 +82,8 @@ namespace MWClass
             const osg::Vec3f& hitPosition, bool success) const override;
 
         void onHit(const MWWorld::Ptr& ptr, float damage, bool ishealth, const MWWorld::Ptr& object,
-            const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const override;
+            const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful,
+            const MWMechanics::DamageSourceType sourceType) const override;
 
         void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector<std::string>& models) const override;
         ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation:
diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp
index 3ce55f8f6c..3f17df96fd 100644
--- a/apps/openmw/mwmechanics/combat.cpp
+++ b/apps/openmw/mwmechanics/combat.cpp
@@ -231,7 +231,8 @@ namespace MWMechanics
 
             if (Misc::Rng::roll0to99(world->getPrng()) >= getHitChance(attacker, victim, skillValue))
             {
-                victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false);
+                victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false,
+                    MWMechanics::DamageSourceType::Ranged);
                 MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker);
                 return;
             }
@@ -287,7 +288,8 @@ namespace MWMechanics
                     victim.getClass().getContainerStore(victim).add(projectile, 1);
             }
 
-            victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true);
+            victim.getClass().onHit(
+                victim, damage, true, projectile, attacker, hitPosition, true, MWMechanics::DamageSourceType::Ranged);
         }
     }
 
diff --git a/apps/openmw/mwmechanics/damagesourcetype.hpp b/apps/openmw/mwmechanics/damagesourcetype.hpp
new file mode 100644
index 0000000000..e140a8106f
--- /dev/null
+++ b/apps/openmw/mwmechanics/damagesourcetype.hpp
@@ -0,0 +1,15 @@
+#ifndef OPENMW_MWMECHANICS_DAMAGESOURCETYPE_H
+#define OPENMW_MWMECHANICS_DAMAGESOURCETYPE_H
+
+namespace MWMechanics
+{
+    enum class DamageSourceType
+    {
+        Unspecified,
+        Melee,
+        Ranged,
+        Magical,
+    };
+}
+
+#endif
diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp
index db9ec3e588..88d978733c 100644
--- a/apps/openmw/mwmechanics/spelleffects.cpp
+++ b/apps/openmw/mwmechanics/spelleffects.cpp
@@ -356,7 +356,8 @@ namespace
         // Notify the target actor they've been hit
         bool isHarmful = magicEffect->mData.mFlags & ESM::MagicEffect::Harmful;
         if (target.getClass().isActor() && target != caster && !caster.isEmpty() && isHarmful)
-            target.getClass().onHit(target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true);
+            target.getClass().onHit(
+                target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true, MWMechanics::DamageSourceType::Magical);
         // Apply resistances
         if (!(effect.mFlags & ESM::ActiveEffect::Flag_Ignore_Resistances))
         {
diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp
index e6080ce447..5fbda6d570 100644
--- a/apps/openmw/mwworld/class.cpp
+++ b/apps/openmw/mwworld/class.cpp
@@ -124,7 +124,7 @@ namespace MWWorld
     }
 
     void Class::onHit(const Ptr& ptr, float damage, bool ishealth, const Ptr& object, const Ptr& attacker,
-        const osg::Vec3f& hitPosition, bool successful) const
+        const osg::Vec3f& hitPosition, bool successful, const MWMechanics::DamageSourceType sourceType) const
     {
         throw std::runtime_error("class cannot be hit");
     }
diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp
index 7b7e9135ba..87e70b3198 100644
--- a/apps/openmw/mwworld/class.hpp
+++ b/apps/openmw/mwworld/class.hpp
@@ -13,6 +13,8 @@
 #include "ptr.hpp"
 
 #include "../mwmechanics/aisetting.hpp"
+#include "../mwmechanics/damagesourcetype.hpp"
+
 #include <components/esm/refid.hpp>
 #include <components/esm3/loadskil.hpp>
 
@@ -142,11 +144,12 @@ namespace MWWorld
         /// (default implementation: throw an exception)
 
         virtual void onHit(const MWWorld::Ptr& ptr, float damage, bool ishealth, const MWWorld::Ptr& object,
-            const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const;
+            const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful,
+            const MWMechanics::DamageSourceType sourceType) const;
         ///< Alerts \a ptr that it's being hit for \a damage points to health if \a ishealth is
         /// true (else fatigue) by \a object (sword, arrow, etc). \a attacker specifies the
-        /// actor responsible for the attack, and \a successful specifies if the hit is
-        /// successful or not.
+        /// actor responsible for the attack. \a successful specifies if the hit is
+        /// successful or not. \a sourceType classifies the damage source.
 
         virtual void block(const Ptr& ptr) const;
         ///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield