[Client] Delimit and clarify combat changes made by tes3mp

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

@ -8,10 +8,18 @@
#include <components/esm/loadnpc.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/Networking.hpp"
#include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/DedicatedPlayer.hpp"
/*
End of tes3mp addition
*/
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -553,8 +561,16 @@ namespace MWClass
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))
return;
/*
End of tes3mp addition
*/
MWBase::World *world = MWBase::Environment::get().getWorld();
@ -564,15 +580,15 @@ namespace MWClass
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
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();
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
const float fCombatDistance = store.find("fCombatDistance")->getFloat();
float dist = fCombatDistance * (!weapon.isEmpty() ?
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
store.find("fHandToHandReach")->getFloat());
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
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.
std::vector<MWWorld::Ptr> targetActors;
@ -582,16 +598,17 @@ namespace MWClass
// TODO: Use second to work out the hit angle
std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist, targetActors);
MWWorld::Ptr victim = result.first;
osg::Vec3f hitPosition(result.second);
if (victim.isEmpty()) // Didn't hit anything
osg::Vec3f hitPosition (result.second);
if(victim.isEmpty()) // Didn't hit anything
return;
const MWWorld::Class &othercls = victim.getClass();
if (!othercls.isActor()) // Can't hit non-actors
if(!othercls.isActor()) // Can't hit non-actors
return;
MWMechanics::CreatureStats &otherstats = othercls.getCreatureStats(victim);
if (otherstats.isDead()) // Can't hit dead actors
if(otherstats.isDead()) // Can't hit dead actors
return;
if(ptr == MWMechanics::getPlayer())
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
@ -601,6 +618,12 @@ namespace MWClass
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())
{
mwmp::Main::get().getLocalPlayer()->attack.success = true;
@ -608,14 +631,26 @@ namespace MWClass
if (dedicatedPlayer != nullptr)
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())
{
mwmp::Main::get().getLocalPlayer()->attack.success = false;
mwmp::Main::get().getLocalPlayer()->sendAttack(mwmp::Attack::MELEE);
}
/*
End of tes3mp addition
*/
othercls.onHit(victim, 0.0f, false, weapon, ptr, osg::Vec3f(), false);
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
@ -763,13 +798,24 @@ namespace MWClass
float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified()
* 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);
bool isDedicated = dedicatedPlayer != nullptr;
bool _knockdown = false;
if(isDedicated)
_knockdown = dedicatedPlayer->attack.knockdown;
bool isDedicatedKnockdown = false;
if (isDedicated)
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);
else
stats.setHitRecovery(true); // Is this supposed to always occur?
@ -871,7 +917,14 @@ namespace MWClass
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);
if (attacker == MWMechanics::getPlayer() && victimPlayer != nullptr)
{
@ -888,13 +941,25 @@ namespace MWClass
mwmp::Main::get().getLocalPlayer()->updateStatsDynamic(true);
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,
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))
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("Not implemented."));
/*
End of tes3mp addition
*/
// player got activated by another NPC
if(ptr == MWMechanics::getPlayer())
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));

@ -1109,6 +1109,12 @@ namespace MWMechanics
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)
{
bool state = MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell();
@ -1117,10 +1123,21 @@ namespace MWMechanics
if (dstate == DrawState_Weapon)
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);
if (dedicatedPlayer != NULL)
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.

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

@ -117,7 +117,12 @@ namespace MWMechanics
int iBlockMinChance = gmst.find("iBlockMinChance")->getInt();
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);
bool isDedicated = dedicatedPlayer != NULL;
if (attacker == MWMechanics::getPlayer())
@ -128,6 +133,9 @@ namespace MWMechanics
{
if (attacker == MWMechanics::getPlayer())
mwmp::Main::get().getLocalPlayer()->attack.block = true;
/*
End of tes3mp change (major)
*/
// Reduce shield durability by incoming damage
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,
const osg::Vec3f& hitPosition, float attackStrength)
{
/*
Start of tes3mp addition
Ignore projectiles fired by DedicatedPlayers
*/
if (mwmp::Main::get().getNetworking()->isDedicatedPlayer(attacker))
return;
/*
End of tes3mp addition
*/
MWBase::World *world = MWBase::Environment::get().getWorld();
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));
/*
Start of tes3mp addition
Mark this as a successful attack for LocalPlayer unless proven otherwise
*/
if (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
mwmp::Main::get().getLocalPlayer()->attack.success = true;
/*
End of tes3mp addition
*/
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())
mwmp::Main::get().getLocalPlayer()->attack.success = false;
/*
End of tes3mp addition
*/
victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false);
MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker);
return;

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

Loading…
Cancel
Save