diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6d198b261..8e59a7aa1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -373,7 +373,20 @@ namespace MWClass } // Apply "On hit" enchanted weapons - MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + /* + Start of tes3mp change (minor) + + Track whether the strike enchantment is successful for attacks by the + LocalPlayer or LocalActors + */ + bool appliedEnchantment = MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + if (localAttack) + localAttack->applyWeaponEnchantment = appliedEnchantment; + /* + End of tes3mp change (minor) + */ } else if (isBipedal(ptr)) { diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index fbf6c6357..ee36c92ae 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -706,7 +706,20 @@ namespace MWClass damage *= store.find("fCombatKODamageMult")->getFloat(); // Apply "On hit" enchanted weapons - MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + /* + Start of tes3mp change (minor) + + Track whether the strike enchantment is successful for attacks by the + LocalPlayer or LocalActors + */ + bool appliedEnchantment = MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + if (localAttack) + localAttack->applyWeaponEnchantment = appliedEnchantment; + /* + End of tes3mp change (minor) + */ MWMechanics::applyElementalShields(ptr, victim); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 91753521a..84f993996 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -290,10 +290,29 @@ namespace MWMechanics reduceWeaponCondition(damage, validVictim, weapon, attacker); // Apply "On hit" effect of the weapon & projectile + + /* + Start of tes3mp change (minor) + + Track whether the strike enchantment is successful for attacks by the + LocalPlayer or LocalActors for both their weapon and projectile + */ + mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); + bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition, true); + + if (localAttack) + localAttack->applyWeaponEnchantment = appliedEnchantment; + if (weapon != projectile) appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, projectile, hitPosition, true); + if (localAttack) + localAttack->applyProjectileEnchantment = appliedEnchantment; + /* + End of tes3mp change (minor) + */ + if (validVictim) { // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index f2eb70c03..cc07dcec9 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -86,13 +86,10 @@ Attack *MechanicsHelper::getDedicatedAttack(const MWWorld::Ptr& ptr) MWWorld::Ptr MechanicsHelper::getPlayerPtr(const Target& target) { - if (target.refId.empty()) - { - if (target.guid == mwmp::Main::get().getLocalPlayer()->guid) - return MWBase::Environment::get().getWorld()->getPlayerPtr(); - else if (PlayerList::getPlayer(target.guid) != nullptr) - return PlayerList::getPlayer(target.guid)->getPtr(); - } + if (target.guid == mwmp::Main::get().getLocalPlayer()->guid) + return MWBase::Environment::get().getWorld()->getPlayerPtr(); + else if (PlayerList::getPlayer(target.guid) != nullptr) + return PlayerList::getPlayer(target.guid)->getPtr(); return nullptr; } @@ -101,18 +98,19 @@ void MechanicsHelper::assignAttackTarget(Attack* attack, const MWWorld::Ptr& tar { if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) { + attack->target.isPlayer = true; attack->target.guid = mwmp::Main::get().getLocalPlayer()->guid; - attack->target.refId.clear(); } else if (mwmp::PlayerList::isDedicatedPlayer(target)) { + attack->target.isPlayer = true; attack->target.guid = mwmp::PlayerList::getPlayer(target)->guid; - attack->target.refId.clear(); } else { MWWorld::CellRef *targetRef = &target.getCellRef(); + attack->target.isPlayer = false; attack->target.refId = targetRef->getRefId(); attack->target.refNumIndex = targetRef->getRefNum().mIndex; attack->target.mpNum = targetRef->getMpNum(); @@ -124,8 +122,12 @@ void MechanicsHelper::resetAttack(Attack* attack) attack->success = false; attack->knockdown = false; attack->block = false; + attack->applyWeaponEnchantment = false; + attack->applyProjectileEnchantment = false; attack->target.guid = RakNet::RakNetGUID(); attack->target.refId.clear(); + attack->target.refNumIndex = 0; + attack->target.mpNum = 0; } bool MechanicsHelper::getSpellSuccess(std::string spellId, const MWWorld::Ptr& caster) @@ -150,7 +152,7 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) MWWorld::Ptr victim; - if (attack.target.refId.empty()) + if (attack.target.isPlayer) { if (attack.target.guid == mwmp::Main::get().getLocalPlayer()->guid) victim = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -170,14 +172,20 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) if (attack.type == Attack::Type::Melee) { MWWorld::Ptr weapon; + MWWorld::Ptr projectile; if (attacker.getClass().hasInventoryStore(attacker)) { - MWWorld::InventoryStore &inv = attacker.getClass().getInventoryStore(attacker); - MWWorld::ContainerStoreIterator weaponslot = inv.getSlot( + MWWorld::InventoryStore &inventoryStore = attacker.getClass().getInventoryStore(attacker); + MWWorld::ContainerStoreIterator weaponSlot = inventoryStore.getSlot( MWWorld::InventoryStore::Slot_CarriedRight); + MWWorld::ContainerStoreIterator projectileSlot = inventoryStore.getSlot( + MWWorld::InventoryStore::Slot_Ammunition); + + // TODO: Fix for when arrows, bolts and throwing weapons have just run out + weapon = weaponSlot != inventoryStore.end() ? *weaponSlot : MWWorld::Ptr(); + projectile = projectileSlot != inventoryStore.end() ? *projectileSlot : MWWorld::Ptr(); - weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr()); if (!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) weapon = MWWorld::Ptr(); } @@ -195,8 +203,26 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) } } else + { + LOG_APPEND(Log::LOG_VERBOSE, "- weapon: %s", weapon.getCellRef().getRefId().c_str()); + MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1); + if (attack.applyWeaponEnchantment) + { + MWMechanics::CastSpell cast(attacker, victim, false); + cast.mHitPosition = osg::Vec3f(); + cast.cast(weapon, false); + } + + if (attack.applyProjectileEnchantment) + { + MWMechanics::CastSpell cast(attacker, victim, false); + cast.mHitPosition = osg::Vec3f(); + cast.cast(projectile, false); + } + } + victim.getClass().onHit(victim, attack.damage, healthdmg, weapon, attacker, osg::Vec3f(), attack.success); } diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index 366555f3c..3994277d0 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -75,7 +75,7 @@ void WorldEvent::addContainerItem(mwmp::WorldObject& worldObject, const MWWorld: containerItem.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge(); containerItem.actionCount = actionCount; - LOG_APPEND(Log::LOG_INFO, "- Adding container item %s", containerItem.refId.c_str()); + LOG_APPEND(Log::LOG_INFO, "-- Adding container item %s", containerItem.refId.c_str()); worldObject.containerItems.push_back(containerItem); } @@ -223,7 +223,12 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) mwmp::Main::get().getCellController()->isLocalActor(ptrFound)) { MWWorld::InventoryStore& invStore = ptrFound.getClass().getInventoryStore(ptrFound); - invStore.autoEquip(ptrFound); + + if (ptrFound.getTypeName() == typeid(ESM::NPC).name()) + invStore.autoEquip(ptrFound); + // autoEquip only works on NPCs, so use the closest alternative for creatures + else + invStore.autoEquipShield(ptrFound); } // If this container was open for us, update its view @@ -324,7 +329,7 @@ void WorldEvent::spawnObjects(MWWorld::CellStore* cellStore) { MWWorld::Ptr masterPtr; - if (worldObject.master.refId.empty()) + if (worldObject.master.isPlayer) masterPtr = MechanicsHelper::getPlayerPtr(worldObject.master); else masterPtr = cellStore->searchExact(worldObject.master.refNumIndex, worldObject.master.mpNum); @@ -814,18 +819,19 @@ void WorldEvent::addObjectSpawn(const MWWorld::Ptr& ptr, const MWWorld::Ptr& mas if (master == MWBase::Environment::get().getWorld()->getPlayerPtr()) { + worldObject.master.isPlayer = true; worldObject.master.guid = mwmp::Main::get().getLocalPlayer()->guid; - worldObject.master.refId.clear(); } else if (mwmp::PlayerList::isDedicatedPlayer(master)) { + worldObject.master.isPlayer = true; worldObject.master.guid = mwmp::PlayerList::getPlayer(master)->guid; - worldObject.master.refId.clear(); } else { MWWorld::CellRef *masterRef = &master.getCellRef(); + worldObject.master.isPlayer = false; worldObject.master.refId = masterRef->getRefId(); worldObject.master.refNumIndex = masterRef->getRefNum().mIndex; worldObject.master.mpNum = masterRef->getMpNum(); diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index ddb0e062b..174cf3b59 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -34,6 +34,8 @@ namespace mwmp struct Target { + bool isPlayer; + std::string refId; int refNumIndex; int mpNum; @@ -66,6 +68,8 @@ namespace mwmp bool pressed; bool instant; bool knockdown; + bool applyWeaponEnchantment; + bool applyProjectileEnchantment; bool shouldSend; }; diff --git a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp index 4ca89cdf9..324f7fb84 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp @@ -11,9 +11,18 @@ PacketActorAttack::PacketActorAttack(RakNet::RakPeerInterface *peer) : ActorPack void PacketActorAttack::Actor(BaseActor &actor, bool send) { - RW(actor.attack.target.refNumIndex, send); - RW(actor.attack.target.mpNum, send); - RW(actor.attack.target.guid, send); + RW(actor.attack.target.isPlayer, send); + + if (actor.attack.target.isPlayer) + { + RW(actor.attack.target.guid, send); + } + else + { + RW(actor.attack.target.refId, send, 1); + RW(actor.attack.target.refNumIndex, send); + RW(actor.attack.target.mpNum, send); + } RW(actor.attack.spellId, send); RW(actor.attack.type, send); @@ -25,4 +34,6 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send) RW(actor.attack.block, send); RW(actor.attack.instant, send); + RW(actor.attack.applyWeaponEnchantment, send); + RW(actor.attack.applyProjectileEnchantment, send); } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp index bde2c9d0c..71dbf9881 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp @@ -16,10 +16,18 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); - RW(player->attack.target.refId, send, 1); - RW(player->attack.target.refNumIndex, send); - RW(player->attack.target.mpNum, send); - RW(player->attack.target.guid, send); + RW(player->attack.target.isPlayer, send); + + if (player->attack.target.isPlayer) + { + RW(player->attack.target.guid, send); + } + else + { + RW(player->attack.target.refId, send, 1); + RW(player->attack.target.refNumIndex, send); + RW(player->attack.target.mpNum, send); + } RW(player->attack.spellId, send, 1); RW(player->attack.type, send); @@ -29,4 +37,7 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) RW(player->attack.pressed, send); RW(player->attack.knockdown, send); RW(player->attack.block, send); + + RW(player->attack.applyWeaponEnchantment, send); + RW(player->attack.applyProjectileEnchantment, send); } diff --git a/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp b/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp index 3716679d7..6d26990f3 100644 --- a/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp +++ b/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp @@ -18,8 +18,17 @@ void PacketObjectSpawn::Object(WorldObject &worldObject, bool send) if (worldObject.hasMaster) { - RW(worldObject.master.refNumIndex, send); - RW(worldObject.master.mpNum, send); - RW(worldObject.master.guid, send); + RW(worldObject.master.isPlayer, send); + + if (worldObject.master.isPlayer) + { + RW(worldObject.master.guid, send); + } + else + { + RW(worldObject.master.refId, send, 1); + RW(worldObject.master.refNumIndex, send); + RW(worldObject.master.mpNum, send); + } } }