diff --git a/CMakeLists.txt b/CMakeLists.txt index c61454e18a..b44ed44fa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 93) +set(OPENMW_LUA_API_REVISION 94) set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 93052567fa..e847ba9d0e 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -349,9 +349,8 @@ namespace MWClass damage, healthdmg, hitPosition, true, MWMechanics::DamageSourceType::Melee); } - void Creature::onHit(const MWWorld::Ptr& ptr, const std::map& damages, - const MWWorld::Ptr& object, const MWWorld::Ptr& attacker, bool successful, - const MWMechanics::DamageSourceType sourceType) const + void Creature::onHit(const MWWorld::Ptr& ptr, const std::map& damages, ESM::RefId object, + const MWWorld::Ptr& attacker, bool successful, const MWMechanics::DamageSourceType sourceType) const { MWMechanics::CreatureStats& stats = getCreatureStats(ptr); @@ -386,8 +385,8 @@ namespace MWClass statsAttacker.setHitAttemptActorId(stats.getActorId()); } - if (!object.isEmpty()) - stats.setLastHitAttemptObject(object.getCellRef().getRefId()); + if (!object.empty()) + stats.setLastHitAttemptObject(object); if (setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { @@ -403,8 +402,8 @@ namespace MWClass return; } - if (!object.isEmpty()) - stats.setLastHitObject(object.getCellRef().getRefId()); + if (!object.empty()) + stats.setLastHitObject(object); bool hasDamage = false; bool hasHealthDamage = false; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index d7bb63011d..64d2251b25 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -66,7 +66,7 @@ namespace MWClass void hit(const MWWorld::Ptr& ptr, float attackStrength, int type, const MWWorld::Ptr& victim, const osg::Vec3f& hitPosition, bool success) const override; - void onHit(const MWWorld::Ptr& ptr, const std::map& damages, const MWWorld::Ptr& object, + void onHit(const MWWorld::Ptr& ptr, const std::map& damages, ESM::RefId object, const MWWorld::Ptr& attacker, bool successful, const MWMechanics::DamageSourceType sourceType) const override; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f56ce35b26..c78a035014 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -700,7 +700,7 @@ namespace MWClass damage, healthdmg, hitPosition, true, MWMechanics::DamageSourceType::Melee); } - void Npc::onHit(const MWWorld::Ptr& ptr, const std::map& damages, const MWWorld::Ptr& object, + void Npc::onHit(const MWWorld::Ptr& ptr, const std::map& damages, ESM::RefId object, const MWWorld::Ptr& attacker, bool successful, const MWMechanics::DamageSourceType sourceType) const { MWMechanics::CreatureStats& stats = getCreatureStats(ptr); @@ -735,8 +735,8 @@ namespace MWClass statsAttacker.setHitAttemptActorId(stats.getActorId()); } - if (!object.isEmpty()) - stats.setLastHitAttemptObject(object.getCellRef().getRefId()); + if (!object.empty()) + stats.setLastHitAttemptObject(object); if (setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { @@ -752,8 +752,8 @@ namespace MWClass return; } - if (!object.isEmpty()) - stats.setLastHitObject(object.getCellRef().getRefId()); + if (!object.empty()) + stats.setLastHitObject(object); if (ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) return; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b038d47337..5a891e0a92 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -81,7 +81,7 @@ namespace MWClass void hit(const MWWorld::Ptr& ptr, float attackStrength, int type, const MWWorld::Ptr& victim, const osg::Vec3f& hitPosition, bool success) const override; - void onHit(const MWWorld::Ptr& ptr, const std::map& damages, const MWWorld::Ptr& object, + void onHit(const MWWorld::Ptr& ptr, const std::map& damages, ESM::RefId object, const MWWorld::Ptr& attacker, bool successful, const MWMechanics::DamageSourceType sourceType) const override; diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 40ec9d93a9..0b760ccdf0 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -515,7 +515,7 @@ namespace MWLua if (!weapon.isEmpty()) data["weapon"] = LObject(weapon); if (!ammo.isEmpty()) - data["ammo"] = LObject(weapon); + data["ammo"] = ammo.getCellRef().getRefId().serializeText(); data["type"] = attackType; data["strength"] = attackStrength; data["damage"] = damageTable; diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 8ce7473061..839f57e621 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -438,20 +438,27 @@ namespace MWLua sourceType = MWMechanics::DamageSourceType::Ranged; else if (sourceTypeStr == "magic") sourceType = MWMechanics::DamageSourceType::Magical; - sol::optional weapon = options.get>("weapon"); - sol::optional ammo = options.get>("ammo"); + std::string_view ammoId = options.get_or("ammo", {}); + ESM::RefId weaponId = ESM::RefId::deserializeText(ammoId); + if (weaponId.empty()) + { + if (sol::optional weapon = options.get>("weapon")) + { + MWWorld::Ptr weaponPtr = weapon->ptrOrEmpty(); + if (!weaponPtr.isEmpty()) + weaponId = weaponPtr.getCellRef().getRefId(); + } + } context.mLuaManager->addAction( [self = Object(self), damages = std::move(damageCpp), - attacker = options.get>("attacker"), weapon = ammo ? ammo : weapon, + attacker = options.get>("attacker"), weaponId, successful = options.get("successful"), sourceType = sourceType] { MWWorld::Ptr attackerPtr; MWWorld::Ptr weaponPtr; if (attacker) attackerPtr = attacker->ptr(); - if (weapon) - weaponPtr = weapon->ptr(); - self.ptr().getClass().onHit(self.ptr(), damages, weaponPtr, attackerPtr, successful, sourceType); + self.ptr().getClass().onHit(self.ptr(), damages, weaponId, attackerPtr, successful, sourceType); }, "HitAction"); }; diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index f8363118bf..c2a7924c77 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -359,7 +359,7 @@ 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, {}, MWWorld::Ptr(), caster, true, MWMechanics::DamageSourceType::Magical); + target.getClass().onHit(target, {}, {}, caster, 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 fc862f302f..7005051659 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -119,7 +119,7 @@ namespace MWWorld throw std::runtime_error("class cannot hit"); } - void Class::onHit(const Ptr& ptr, const std::map& damages, const Ptr& object, + void Class::onHit(const Ptr& ptr, const std::map& damages, ESM::RefId object, const Ptr& attacker, 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 5633c90b12..0d436afd66 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -147,9 +147,8 @@ namespace MWWorld /// enums. ignored for creature attacks. /// (default implementation: throw an exception) - virtual void onHit(const MWWorld::Ptr& ptr, const std::map& damages, - const MWWorld::Ptr& object, const MWWorld::Ptr& attacker, bool successful, - const MWMechanics::DamageSourceType sourceType) const; + virtual void onHit(const MWWorld::Ptr& ptr, const std::map& damages, ESM::RefId object, + const MWWorld::Ptr& attacker, bool successful, const MWMechanics::DamageSourceType sourceType) const; ///< Alerts \a ptr that it's being hit for \a damages by \a object (sword, arrow, etc). \a attacker specifies ///< the /// actor responsible for the attack. \a successful specifies if the hit is diff --git a/files/data/scripts/omw/combat/local.lua b/files/data/scripts/omw/combat/local.lua index 504f10a1fd..7c688d6569 100644 --- a/files/data/scripts/omw/combat/local.lua +++ b/files/data/scripts/omw/combat/local.lua @@ -192,7 +192,7 @@ local function applyArmor(attack) I.SkillProgression.skillUsed(skillid, {useType = I.SkillProgression.SKILL_USE_TYPES.Armor_HitByOpponent}) end if item and Armor.objectIsInstance(item) then - local attackerIsUnarmedCreature = attack.attacker and not attack.weapon and Creature.objectIsInstance(attack.attacker) + local attackerIsUnarmedCreature = attack.attacker and not attack.weapon and not attack.ammo and Creature.objectIsInstance(attack.attacker) if settings:get('unarmedCreatureAttacksDamageArmor') or not attackerIsUnarmedCreature then core.sendGlobalEvent('ModifyItemCondition', { actor = self, item = item, amount = diff }) end @@ -307,7 +307,7 @@ end -- @field [parent=#AttackInfo] openmw.self#ATTACK_TYPE type (Optional) Attack variant if applicable. For melee attacks this represents chop vs thrust vs slash. For unarmed creatures this implies which of its 3 possible attacks were used. For other attacks this field can be ignored. -- @field [parent=#AttackInfo] openmw.types#Actor attacker (Optional) Attacking actor -- @field [parent=#AttackInfo] openmw.types#Weapon weapon (Optional) Attacking weapon --- @field [parent=#AttackInfo] openmw.types#Weapon ammo (Optional) Ammo +-- @field [parent=#AttackInfo] #string ammo (Optional) Ammo record ID -- @field [parent=#AttackInfo] openmw.util#Vector3 hitPos (Optional) Where on the victim the attack is landing. Used to spawn blood effects. Blood effects are skipped if nil. return { --- Basic combat interface @@ -330,7 +330,7 @@ return { interface = { --- Interface version -- @field [parent=#Combat] #number version - version = 0, + version = 1, --- Add new onHit handler for this actor -- If `handler(attack)` returns false, other handlers for