[Client] Delimit and clarify combat changes made by tes3mp

Additionally, revert unneeded small changes to the formatting of OpenMW code
pull/199/head
David Cernat 8 years ago
parent 9f226253d4
commit 2565816b22

@ -8,10 +8,18 @@
#include <components/esm/loadnpc.hpp> #include <components/esm/loadnpc.hpp>
#include <components/esm/npcstate.hpp> #include <components/esm/npcstate.hpp>
#include "../mwmp/DedicatedPlayer.hpp" /*
#include "../mwmp/Networking.hpp" Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
#include "../mwmp/Main.hpp" #include "../mwmp/Main.hpp"
#include "../mwmp/Networking.hpp"
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/DedicatedPlayer.hpp"
/*
End of tes3mp addition
*/
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -553,8 +561,16 @@ namespace MWClass
void Npc::hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const void Npc::hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const
{ {
/*
Start of tes3mp addition
Ignore hits from DedicatedPlayers
*/
if (mwmp::Main::get().getNetworking()->isDedicatedPlayer(ptr)) if (mwmp::Main::get().getNetworking()->isDedicatedPlayer(ptr))
return; return;
/*
End of tes3mp addition
*/
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
@ -564,15 +580,15 @@ namespace MWClass
MWWorld::InventoryStore &inv = getInventoryStore(ptr); MWWorld::InventoryStore &inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
MWWorld::Ptr weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr()); MWWorld::Ptr weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr());
if (!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
weapon = MWWorld::Ptr(); weapon = MWWorld::Ptr();
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength); MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
const float fCombatDistance = store.find("fCombatDistance")->getFloat(); const float fCombatDistance = store.find("fCombatDistance")->getFloat();
float dist = fCombatDistance * (!weapon.isEmpty() ? float dist = fCombatDistance * (!weapon.isEmpty() ?
weapon.get<ESM::Weapon>()->mBase->mData.mReach : weapon.get<ESM::Weapon>()->mBase->mData.mReach :
store.find("fHandToHandReach")->getFloat()); store.find("fHandToHandReach")->getFloat());
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result. // For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
std::vector<MWWorld::Ptr> targetActors; std::vector<MWWorld::Ptr> targetActors;
@ -582,16 +598,17 @@ namespace MWClass
// TODO: Use second to work out the hit angle // TODO: Use second to work out the hit angle
std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist, targetActors); std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist, targetActors);
MWWorld::Ptr victim = result.first; MWWorld::Ptr victim = result.first;
osg::Vec3f hitPosition(result.second); osg::Vec3f hitPosition (result.second);
if (victim.isEmpty()) // Didn't hit anything if(victim.isEmpty()) // Didn't hit anything
return; return;
const MWWorld::Class &othercls = victim.getClass(); const MWWorld::Class &othercls = victim.getClass();
if (!othercls.isActor()) // Can't hit non-actors if(!othercls.isActor()) // Can't hit non-actors
return; return;
MWMechanics::CreatureStats &otherstats = othercls.getCreatureStats(victim); MWMechanics::CreatureStats &otherstats = othercls.getCreatureStats(victim);
if (otherstats.isDead()) // Can't hit dead actors if(otherstats.isDead()) // Can't hit dead actors
return; return;
if(ptr == MWMechanics::getPlayer()) if(ptr == MWMechanics::getPlayer())
MWBase::Environment::get().getWindowManager()->setEnemy(victim); MWBase::Environment::get().getWindowManager()->setEnemy(victim);
@ -601,6 +618,12 @@ namespace MWClass
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
/*
Start of tes3mp addition
If the attacker is a LocalPlayer and the target is a DedicatedPlayer,
mark that accordingly in the LocalPlayer data
*/
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
{ {
mwmp::Main::get().getLocalPlayer()->attack.success = true; mwmp::Main::get().getLocalPlayer()->attack.success = true;
@ -608,14 +631,26 @@ namespace MWClass
if (dedicatedPlayer != nullptr) if (dedicatedPlayer != nullptr)
mwmp::Main::get().getLocalPlayer()->attack.target = dedicatedPlayer->guid; mwmp::Main::get().getLocalPlayer()->attack.target = dedicatedPlayer->guid;
} }
/*
End of tes3mp addition
*/
if(Misc::Rng::roll0to99() >= hitchance) if (Misc::Rng::roll0to99() >= hitchance)
{ {
/*
Start of tes3mp addition
If this was a failed attack by the LocalPlayer, send a
PlayerAttack packet about it
*/
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
{ {
mwmp::Main::get().getLocalPlayer()->attack.success = false; mwmp::Main::get().getLocalPlayer()->attack.success = false;
mwmp::Main::get().getLocalPlayer()->sendAttack(mwmp::Attack::MELEE); mwmp::Main::get().getLocalPlayer()->sendAttack(mwmp::Attack::MELEE);
} }
/*
End of tes3mp addition
*/
othercls.onHit(victim, 0.0f, false, weapon, ptr, osg::Vec3f(), false); othercls.onHit(victim, 0.0f, false, weapon, ptr, osg::Vec3f(), false);
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
@ -763,13 +798,24 @@ namespace MWClass
float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified()
* gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt();
/*
Start of tes3mp change (major)
If the attacker is a DedicatedPlayer with a successful knockdown, apply the knockdown;
otherwise, use default probability roll
*/
mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(attacker); mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(attacker);
bool isDedicated = dedicatedPlayer != nullptr; bool isDedicated = dedicatedPlayer != nullptr;
bool _knockdown = false; bool isDedicatedKnockdown = false;
if(isDedicated) if (isDedicated)
_knockdown = dedicatedPlayer->attack.knockdown; isDedicatedKnockdown = dedicatedPlayer->attack.knockdown;
if ((!isDedicated && ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) || _knockdown) if (isDedicatedKnockdown)
stats.setKnockedDown(true);
else if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
/*
End of tes3mp change (major)
*/
stats.setKnockedDown(true); stats.setKnockedDown(true);
else else
stats.setHitRecovery(true); // Is this supposed to always occur? stats.setHitRecovery(true); // Is this supposed to always occur?
@ -871,7 +917,14 @@ namespace MWClass
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker); MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
} }
/*
Start of tes3mp addition
If the victim was a DedicatedPlayer, send a PlayerAttack packet from LocalPlayer
If the victim was the LocalPlayer, check whether packets should be sent about
their new dynamic stats and position
*/
mwmp::DedicatedPlayer *victimPlayer = mwmp::Players::getPlayer(ptr); mwmp::DedicatedPlayer *victimPlayer = mwmp::Players::getPlayer(ptr);
if (attacker == MWMechanics::getPlayer() && victimPlayer != nullptr) if (attacker == MWMechanics::getPlayer() && victimPlayer != nullptr)
{ {
@ -888,13 +941,25 @@ namespace MWClass
mwmp::Main::get().getLocalPlayer()->updateStatsDynamic(true); mwmp::Main::get().getLocalPlayer()->updateStatsDynamic(true);
mwmp::Main::get().getLocalPlayer()->updatePosition(true); // fix position after getting damage; mwmp::Main::get().getLocalPlayer()->updatePosition(true); // fix position after getting damage;
} }
/*
End of tes3mp addition
*/
} }
boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const const MWWorld::Ptr& actor) const
{ {
/*
Start of tes3mp addition
Don't display a dialogue screen for two players interacting with each other
*/
if (actor == MWMechanics::getPlayer() && mwmp::Main::get().getNetworking()->isDedicatedPlayer(ptr)) if (actor == MWMechanics::getPlayer() && mwmp::Main::get().getNetworking()->isDedicatedPlayer(ptr))
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("Not implemented.")); return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("Not implemented."));
/*
End of tes3mp addition
*/
// player got activated by another NPC // player got activated by another NPC
if(ptr == MWMechanics::getPlayer()) if(ptr == MWMechanics::getPlayer())
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor)); return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));

@ -1109,6 +1109,12 @@ namespace MWMechanics
iter->second->getCharacterController()->setActive(inProcessingRange); iter->second->getCharacterController()->setActive(inProcessingRange);
/*
Start of tes3mp change (minor)
Instead of merely updating the player character's mAttackingOrSpell here,
send a PlayerAttack packet from LocalPlayer when applicable
*/
if (iter->first == player) if (iter->first == player)
{ {
bool state = MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell(); bool state = MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell();
@ -1117,10 +1123,21 @@ namespace MWMechanics
if (dstate == DrawState_Weapon) if (dstate == DrawState_Weapon)
mwmp::Main::get().getLocalPlayer()->prepareAttack(mwmp::Attack::MELEE, state); mwmp::Main::get().getLocalPlayer()->prepareAttack(mwmp::Attack::MELEE, state);
} }
/*
End of tes3mp change (minor)
*/
/*
Start of tes3mp addition
If this actor is a DedicatedPlayer, update their mAttackingOrSpell
*/
mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(iter->first); mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(iter->first);
if (dedicatedPlayer != NULL) if (dedicatedPlayer != NULL)
dedicatedPlayer->updateActor(iter->second); dedicatedPlayer->updateActor(iter->second);
/*
End of tes3mp addition
*/
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player. // If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.

@ -1254,8 +1254,16 @@ bool CharacterController::updateWeaponState()
if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr)) if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
{ {
/*
Start of tes3mp addition
Send PlayerAttack packet for this spell
*/
if (mPtr == getPlayer()) if (mPtr == getPlayer())
mwmp::Main::get().getLocalPlayer()->prepareAttack(mwmp::Attack::MAGIC, true); mwmp::Main::get().getLocalPlayer()->prepareAttack(mwmp::Attack::MAGIC, true);
/*
End of tes3mp addition
*/
MWMechanics::CastSpell cast(mPtr, NULL); MWMechanics::CastSpell cast(mPtr, NULL);
cast.playSpellCastingEffects(spellid); cast.playSpellCastingEffects(spellid);

@ -117,7 +117,12 @@ namespace MWMechanics
int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); int iBlockMinChance = gmst.find("iBlockMinChance")->getInt();
x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x));
/*
Start of tes3mp change (major)
Only calculate block chance for blockers who are not DedicatedPlayers
and update block state for LocalPlayer
*/
mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(blocker); mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(blocker);
bool isDedicated = dedicatedPlayer != NULL; bool isDedicated = dedicatedPlayer != NULL;
if (attacker == MWMechanics::getPlayer()) if (attacker == MWMechanics::getPlayer())
@ -128,6 +133,9 @@ namespace MWMechanics
{ {
if (attacker == MWMechanics::getPlayer()) if (attacker == MWMechanics::getPlayer())
mwmp::Main::get().getLocalPlayer()->attack.block = true; mwmp::Main::get().getLocalPlayer()->attack.block = true;
/*
End of tes3mp change (major)
*/
// Reduce shield durability by incoming damage // Reduce shield durability by incoming damage
int shieldhealth = shield->getClass().getItemHealth(*shield); int shieldhealth = shield->getClass().getItemHealth(*shield);
@ -183,8 +191,17 @@ namespace MWMechanics
void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile,
const osg::Vec3f& hitPosition, float attackStrength) const osg::Vec3f& hitPosition, float attackStrength)
{ {
/*
Start of tes3mp addition
Ignore projectiles fired by DedicatedPlayers
*/
if (mwmp::Main::get().getNetworking()->isDedicatedPlayer(attacker)) if (mwmp::Main::get().getNetworking()->isDedicatedPlayer(attacker))
return; return;
/*
End of tes3mp addition
*/
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
@ -202,13 +219,31 @@ namespace MWMechanics
int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon));
/*
Start of tes3mp addition
Mark this as a successful attack for LocalPlayer unless proven otherwise
*/
if (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) if (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
mwmp::Main::get().getLocalPlayer()->attack.success = true; mwmp::Main::get().getLocalPlayer()->attack.success = true;
/*
End of tes3mp addition
*/
if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue)) if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue))
{ {
/*
Start of tes3mp addition
Mark this as a failed attack for LocalPlayer now that the hit roll
has failed
*/
if (attacker == getPlayer()) if (attacker == getPlayer())
mwmp::Main::get().getLocalPlayer()->attack.success = false; mwmp::Main::get().getLocalPlayer()->attack.success = false;
/*
End of tes3mp addition
*/
victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false); victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false);
MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker); MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker);
return; return;

@ -836,17 +836,18 @@ namespace MWMechanics
bool fail = false; bool fail = false;
// Major change done by tes3mp: /*
// Start of tes3mp change (major)
// Instead of checking whether the caster is a player or an NPC,
// first check whether it's the LocalPlayer or a DedicatedPlayer and calculate Instead of checking whether the caster is a player or an NPC,
// calculate the success chance in clients' LocalPlayer::prepareAttack() first check whether it's the LocalPlayer or a DedicatedPlayer and calculate
// calculate the success chance in clients' LocalPlayer::prepareAttack()
// TODO: Make this make sense for NPCs too
// TODO: Make this make sense for NPCs too
// TODO: See if LocalPlayer being the target and having godmode on
// can be accounted for like it is in OpenMW's corresponding code TODO: See if LocalPlayer being the target and having godmode on
can be accounted for like it is in OpenMW's corresponding code
*/
mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(mCaster); mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::Players::getPlayer(mCaster);
bool isDedicated = dedicatedPlayer != NULL; bool isDedicated = dedicatedPlayer != NULL;
@ -864,6 +865,9 @@ namespace MWMechanics
fail = true; fail = true;
} }
else if (!(mCaster == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())) else if (!(mCaster == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()))
/*
End of tes3mp change (major)
*/
{ {
float successChance = getSpellSuccessChance(spell, mCaster); float successChance = getSpellSuccessChance(spell, mCaster);
if (Misc::Rng::roll0to99() >= successChance) if (Misc::Rng::roll0to99() >= successChance)

Loading…
Cancel
Save