1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-04-01 15:36:42 +00:00

[Client] Rethink and restructure tes3mp combat code so it works for NPCs

This commit is contained in:
David Cernat 2017-04-19 22:06:04 +03:00
parent 6c2bbd6608
commit 2e8714afaa
13 changed files with 224 additions and 140 deletions

View file

@ -13,9 +13,12 @@
Include additional headers for multiplayer purposes Include additional headers for multiplayer purposes
*/ */
#include <components/openmw-mp/Log.hpp>
#include "../mwmp/Main.hpp" #include "../mwmp/Main.hpp"
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/DedicatedPlayer.hpp" #include "../mwmp/DedicatedPlayer.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/MechanicsHelper.hpp"
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -563,10 +566,12 @@ namespace MWClass
/* /*
Start of tes3mp addition Start of tes3mp addition
Ignore hit calculations on this client from DedicatedPlayers Ignore hit calculations on this client from DedicatedPlayers and DedicatedActors
*/ */
if (mwmp::PlayerList::isDedicatedPlayer(ptr)) if (mwmp::PlayerList::isDedicatedPlayer(ptr) || mwmp::Main::get().getCellController()->isDedicatedActor(ptr))
{
return; return;
}
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -620,15 +625,15 @@ namespace MWClass
/* /*
Start of tes3mp addition Start of tes3mp addition
If the attacker is a LocalPlayer and the target is a DedicatedPlayer, If the attacker is a LocalPlayer or LocalActor, get their Attack and
mark that accordingly in the LocalPlayer data assign data for its target
*/ */
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) mwmp::Attack *localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(ptr);
{
mwmp::Main::get().getLocalPlayer()->attack.success = true;
if (mwmp::PlayerList::isDedicatedPlayer(victim)) if (localAttack)
mwmp::Main::get().getLocalPlayer()->attack.target.guid = mwmp::PlayerList::getPlayer(victim)->guid; {
localAttack->success = true;
mwmp::Main::get().getMechanicsHelper()->assignAttackTarget(localAttack, victim);
} }
/* /*
End of tes3mp addition End of tes3mp addition
@ -639,13 +644,14 @@ namespace MWClass
/* /*
Start of tes3mp addition Start of tes3mp addition
If this was a failed attack by the LocalPlayer, send a If this was a failed attack by the LocalPlayer or LocalActor, send a
PlayerAttack packet about it packet about it
*/ */
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) if (localAttack)
{ {
mwmp::Main::get().getLocalPlayer()->attack.success = false; localAttack->pressed = false;
mwmp::Main::get().getLocalPlayer()->sendAttack(mwmp::Attack::MELEE); localAttack->success = false;
localAttack->shouldSend = true;
} }
/* /*
End of tes3mp addition End of tes3mp addition
@ -800,10 +806,12 @@ namespace MWClass
/* /*
Start of tes3mp change (major) Start of tes3mp change (major)
If the attacker is a DedicatedPlayer with a successful knockdown, apply the knockdown; If the attacker is a DedicatedPlayer or DedicatedActor with a successful knockdown, apply the knockdown;
otherwise, use default probability roll otherwise, use default probability roll
*/ */
if (mwmp::PlayerList::isDedicatedPlayer(attacker) && mwmp::PlayerList::getPlayer(attacker)->attack.knockdown) mwmp::Attack *dedicatedAttack = mwmp::Main::get().getMechanicsHelper()->getDedicatedAttack(attacker);
if (dedicatedAttack && dedicatedAttack->knockdown)
stats.setKnockedDown(true); stats.setKnockedDown(true);
else if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) else if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
/* /*
@ -913,24 +921,24 @@ namespace MWClass
/* /*
Start of tes3mp addition Start of tes3mp addition
If the victim was a DedicatedPlayer, send a PlayerAttack packet from LocalPlayer If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it
If the victim was the LocalPlayer, check whether packets should be sent about If the victim was the LocalPlayer, check whether packets should be sent about
their new dynamic stats and position their new dynamic stats and position
*/ */
if (attacker == MWMechanics::getPlayer() && mwmp::PlayerList::isDedicatedPlayer(ptr)) mwmp::Attack *localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(attacker);
if (localAttack)
{ {
mwmp::DedicatedPlayer *victimPlayer = mwmp::PlayerList::getPlayer(ptr); localAttack->pressed = false;
localAttack->damage = damage;
localAttack->knockdown = getCreatureStats(ptr).getKnockedDown();
mwmp::Attack *attack = &mwmp::Main::get().getLocalPlayer()->attack; mwmp::Main::get().getMechanicsHelper()->assignAttackTarget(localAttack, ptr);
attack->damage = damage;
attack->target.guid = victimPlayer->guid;
attack->knockdown = getCreatureStats(ptr).getKnockedDown();
mwmp::Main::get().getLocalPlayer()->sendAttack(mwmp::Attack::MELEE); // todo: make this sensitive to different weapon types localAttack->shouldSend = true;
} }
else if (ptr == MWMechanics::getPlayer())
if (ptr == MWMechanics::getPlayer())
{ {
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;

View file

@ -16,10 +16,12 @@
Include additional headers for multiplayer purposes Include additional headers for multiplayer purposes
*/ */
#include <components/openmw-mp/Log.hpp>
#include "../mwmp/Main.hpp" #include "../mwmp/Main.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/DedicatedPlayer.hpp"
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/DedicatedPlayer.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/MechanicsHelper.hpp"
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -1120,15 +1122,26 @@ namespace MWMechanics
Start of tes3mp change (minor) Start of tes3mp change (minor)
Instead of merely updating the player character's mAttackingOrSpell here, Instead of merely updating the player character's mAttackingOrSpell here,
send a PlayerAttack packet from LocalPlayer when applicable prepare an Attack packet for the LocalPlayer
*/ */
if (iter->first == player) if (iter->first == player)
{ {
bool state = MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell(); bool state = MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell();
DrawState_ dstate = player.getClass().getNpcStats(player).getDrawState(); DrawState_ dstate = player.getClass().getNpcStats(player).getDrawState();
iter->second->getCharacterController()->setAttackingOrSpell(state); iter->second->getCharacterController()->setAttackingOrSpell(state);
if (dstate == DrawState_Weapon) if (dstate == DrawState_Weapon)
mwmp::Main::get().getLocalPlayer()->prepareAttack(mwmp::Attack::MELEE, state); {
mwmp::Attack *localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(iter->first);
if (localAttack->pressed != state)
{
mwmp::Main::get().getMechanicsHelper()->resetAttack(localAttack);
localAttack->type = mwmp::Attack::MELEE;
localAttack->pressed = state;
localAttack->shouldSend = true;
}
}
} }
/* /*
End of tes3mp change (minor) End of tes3mp change (minor)
@ -1137,10 +1150,12 @@ namespace MWMechanics
/* /*
Start of tes3mp addition Start of tes3mp addition
If this actor is a DedicatedPlayer, update their mAttackingOrSpell If this actor is a DedicatedPlayer or DedicatedActor, update their mAttackingOrSpell
*/ */
if (mwmp::PlayerList::isDedicatedPlayer(iter->first)) mwmp::Attack *dedicatedAttack = mwmp::Main::get().getMechanicsHelper()->getDedicatedAttack(iter->first);
mwmp::PlayerList::getPlayer(iter->first)->updateActor(iter->second);
if (dedicatedAttack)
iter->second->getCharacterController()->setAttackingOrSpell(dedicatedAttack->pressed);
/* /*
End of tes3mp addition End of tes3mp addition
*/ */

View file

@ -4,6 +4,18 @@
#include <components/esm/aisequence.hpp> #include <components/esm/aisequence.hpp>
/*
Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
#include <components/openmw-mp/Log.hpp>
#include "../mwmp/Main.hpp"
#include "../mwmp/MechanicsHelper.hpp"
/*
End of tes3mp addition
*/
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
@ -233,6 +245,25 @@ namespace MWMechanics
{ {
storage.stopAttack(); storage.stopAttack();
characterController.setAttackingOrSpell(false); characterController.setAttackingOrSpell(false);
/*
Start of tes3mp addition
Record that this actor is stopping an attack so that a packet will be sent about it
*/
mwmp::Attack *localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(actor);
if (localAttack->pressed != false)
{
mwmp::Main::get().getMechanicsHelper()->resetAttack(localAttack);
localAttack->type = mwmp::Attack::MELEE;
localAttack->pressed = false;
localAttack->shouldSend = true;
}
/*
End of tes3mp addition
*/
storage.mActionCooldown = 0.f; storage.mActionCooldown = 0.f;
// Continue combat if target is player or player follower/escorter and an attack has been attempted // Continue combat if target is player or player follower/escorter and an attack has been attempted
const std::list<MWWorld::Ptr>& playerFollowersAndEscorters = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(MWMechanics::getPlayer()); const std::list<MWWorld::Ptr>& playerFollowersAndEscorters = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(MWMechanics::getPlayer());
@ -566,6 +597,24 @@ namespace MWMechanics
mAttack = true; // attack starts just now mAttack = true; // attack starts just now
characterController.setAttackingOrSpell(true); characterController.setAttackingOrSpell(true);
/*
Start of tes3mp addition
Record that this actor is starting an attack so that a packet will be sent about it
*/
mwmp::Attack *localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(actor);
if (localAttack->pressed != true)
{
mwmp::Main::get().getMechanicsHelper()->resetAttack(localAttack);
localAttack->type = mwmp::Attack::MELEE;
localAttack->pressed = true;
localAttack->shouldSend = true;
}
/*
End of tes3mp addition
*/
if (!distantCombat) if (!distantCombat)
characterController.setAIAttackType(chooseBestAttack(weapon)); characterController.setAIAttackType(chooseBestAttack(weapon));

View file

@ -34,10 +34,11 @@
*/ */
#include <components/openmw-mp/Log.hpp> #include <components/openmw-mp/Log.hpp>
#include "../mwmp/Main.hpp" #include "../mwmp/Main.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/LocalActor.hpp" #include "../mwmp/LocalActor.hpp"
#include "../mwmp/DedicatedPlayer.hpp" #include "../mwmp/DedicatedPlayer.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/MechanicsHelper.hpp"
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -1258,10 +1259,18 @@ bool CharacterController::updateWeaponState()
/* /*
Start of tes3mp addition Start of tes3mp addition
Send PlayerAttack packet for this spell If this mPtr belongs to a LocalPlayer or LocalActor, get their Attack and prepare
it for sending
*/ */
if (mPtr == getPlayer()) mwmp::Attack *localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(mPtr);
mwmp::Main::get().getLocalPlayer()->prepareAttack(mwmp::Attack::MAGIC, true);
if (localAttack)
{
mwmp::Main::get().getMechanicsHelper()->resetAttack(localAttack);
localAttack->type = mwmp::Attack::MAGIC;
localAttack->pressed = true;
localAttack->shouldSend = true;
}
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -1349,10 +1358,11 @@ bool CharacterController::updateWeaponState()
/* /*
Start of tes3mp change (major) Start of tes3mp change (major)
We need player-controlled NPCs to not have their attacks We need DedicatedPlayers and DedicatedActors to not have their attacks
cancelled here, so a 2nd condition has been added for them cancelled here, so additional conditions have been added for them
*/ */
if(mPtr == getPlayer() || mwmp::PlayerList::isDedicatedPlayer(mPtr)) if(mPtr == getPlayer() || mwmp::PlayerList::isDedicatedPlayer(mPtr) ||
mwmp::Main::get().getCellController()->isDedicatedActor(mPtr))
/* /*
End of tes3mp change (major) End of tes3mp change (major)
*/ */

View file

@ -9,9 +9,12 @@
Include additional headers for multiplayer purposes Include additional headers for multiplayer purposes
*/ */
#include <components/openmw-mp/Log.hpp>
#include "../mwmp/Main.hpp" #include "../mwmp/Main.hpp"
#include "../mwmp/DedicatedPlayer.hpp"
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/DedicatedPlayer.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/MechanicsHelper.hpp"
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -127,19 +130,25 @@ namespace MWMechanics
/* /*
Start of tes3mp change (major) Start of tes3mp change (major)
Only calculate block chance for blockers who are not DedicatedPlayers Only calculate block chance for LocalPlayers and LocalActors; otherwise,
and update block state for LocalPlayer get the block state from the relevant DedicatedPlayer or DedicatedActor
*/ */
if (attacker == MWMechanics::getPlayer()) mwmp::Attack *localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(attacker);
mwmp::Main::get().getLocalPlayer()->attack.block = false;
bool isDedicated = mwmp::PlayerList::isDedicatedPlayer(blocker); if (localAttack)
if ((!isDedicated && Misc::Rng::roll0to99() < x) ||
(isDedicated && mwmp::PlayerList::getPlayer(blocker)->attack.block == true))
{ {
if (attacker == MWMechanics::getPlayer()) localAttack->block = false;
mwmp::Main::get().getLocalPlayer()->attack.block = true; }
mwmp::Attack *dedicatedAttack = mwmp::Main::get().getMechanicsHelper()->getDedicatedAttack(blocker);
if ((dedicatedAttack && dedicatedAttack->block == true) ||
Misc::Rng::roll0to99() < x)
{
if (localAttack)
{
localAttack->block = true;
}
/* /*
End of tes3mp change (major) End of tes3mp change (major)
*/ */

View file

@ -13,9 +13,11 @@
Include additional headers for multiplayer purposes Include additional headers for multiplayer purposes
*/ */
#include <components/openmw-mp/Log.hpp>
#include "../mwmp/Main.hpp" #include "../mwmp/Main.hpp"
#include "../mwmp/DedicatedPlayer.hpp" #include "../mwmp/DedicatedPlayer.hpp"
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/MechanicsHelper.hpp"
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -856,16 +858,17 @@ namespace MWMechanics
TODO: See if LocalPlayer being the target and having godmode on TODO: See if LocalPlayer being the target and having godmode on
can be accounted for like it is in OpenMW's corresponding code can be accounted for like it is in OpenMW's corresponding code
*/ */
mwmp::DedicatedPlayer *dedicatedPlayer = mwmp::PlayerList::getPlayer(mCaster); mwmp::Attack *localAttack = NULL;
mwmp::Attack *dedicatedAttack = mwmp::Main::get().getMechanicsHelper()->getDedicatedAttack(mCaster);
bool isDedicated = mwmp::PlayerList::isDedicatedPlayer(mCaster); if (dedicatedAttack)
dedicatedAttack->pressed = false;
if (isDedicated) else
dedicatedPlayer->attack.pressed = false; localAttack = mwmp::Main::get().getMechanicsHelper()->getLocalAttack(mCaster);
// Check success // Check success
if ((!isDedicated && !mwmp::Main::get().getLocalPlayer()->attack.success) || if ((localAttack && localAttack->success == false) ||
(isDedicated && dedicatedPlayer->attack.success == false)) (dedicatedAttack && dedicatedAttack->success == false))
{ {
if (mCaster == getPlayer()) if (mCaster == getPlayer())
{ {

View file

@ -235,7 +235,7 @@ DedicatedPlayer *PlayerList::getPlayer(const MWWorld::Ptr &ptr)
bool PlayerList::isDedicatedPlayer(const MWWorld::Ptr &ptr) bool PlayerList::isDedicatedPlayer(const MWWorld::Ptr &ptr)
{ {
if (ptr.mRef == 0) if (ptr.mRef == NULL)
return false; return false;
return (getPlayer(ptr) != 0); return (getPlayer(ptr) != 0);
@ -420,11 +420,6 @@ void DedicatedPlayer::setMarkerState(bool state)
removeMarker(); removeMarker();
} }
void DedicatedPlayer::updateActor(MWMechanics::Actor *actor)
{
actor->getCharacterController()->setAttackingOrSpell(attack.pressed);
}
MWWorld::Ptr DedicatedPlayer::getPtr() MWWorld::Ptr DedicatedPlayer::getPtr()
{ {
return ptr; return ptr;

View file

@ -61,7 +61,6 @@ namespace mwmp
void updateMarker(); void updateMarker();
void removeMarker(); void removeMarker();
void setMarkerState(bool state); void setMarkerState(bool state);
void updateActor(MWMechanics::Actor *actor);
MWWorld::Ptr getPtr(); MWWorld::Ptr getPtr();
MWWorld::Ptr getLiveCellPtr(); MWWorld::Ptr getLiveCellPtr();

View file

@ -14,6 +14,7 @@
#include "Main.hpp" #include "Main.hpp"
#include "Networking.hpp" #include "Networking.hpp"
#include "ActorList.hpp" #include "ActorList.hpp"
#include "MechanicsHelper.hpp"
using namespace mwmp; using namespace mwmp;
using namespace std; using namespace std;
@ -32,6 +33,9 @@ LocalActor::LocalActor()
statTimer = 0; statTimer = 0;
attack.type = Attack::MELEE;
attack.shouldSend = false;
creatureStats = new ESM::CreatureStats(); creatureStats = new ESM::CreatureStats();
} }
@ -47,6 +51,7 @@ void LocalActor::update(bool forceUpdate)
updateAnimPlay(); updateAnimPlay();
updateSpeech(); updateSpeech();
updateStatsDynamic(forceUpdate); updateStatsDynamic(forceUpdate);
updateAttack();
} }
void LocalActor::updatePosition(bool forceUpdate) void LocalActor::updatePosition(bool forceUpdate)
@ -168,6 +173,22 @@ void LocalActor::updateStatsDynamic(bool forceUpdate)
} }
} }
void LocalActor::updateAttack()
{
if (attack.shouldSend)
{
if (attack.type == Attack::MAGIC)
{
MWMechanics::CreatureStats &attackerStats = ptr.getClass().getNpcStats(ptr);
attack.spellId = attackerStats.getSpells().getSelectedSpell();
attack.success = mwmp::Main::get().getMechanicsHelper()->getSpellSuccess(attack.spellId, ptr);
}
mwmp::Main::get().getNetworking()->getActorList()->addAttackActor(*this);
attack.shouldSend = false;
}
}
MWWorld::Ptr LocalActor::getPtr() MWWorld::Ptr LocalActor::getPtr()
{ {
return ptr; return ptr;

View file

@ -21,6 +21,7 @@ namespace mwmp
void updateAnimPlay(); void updateAnimPlay();
void updateSpeech(); void updateSpeech();
void updateStatsDynamic(bool forceUpdate); void updateStatsDynamic(bool forceUpdate);
void updateAttack();
MWWorld::Ptr getPtr(); MWWorld::Ptr getPtr();
void setPtr(const MWWorld::Ptr& newPtr); void setPtr(const MWWorld::Ptr& newPtr);

View file

@ -2,7 +2,6 @@
// Created by koncord on 14.01.16. // Created by koncord on 14.01.16.
// //
#include <components/misc/rng.hpp>
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/openmw-mp/Log.hpp> #include <components/openmw-mp/Log.hpp>
@ -22,7 +21,6 @@
#include "../mwmechanics/aitravel.hpp" #include "../mwmechanics/aitravel.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwscript/scriptmanagerimp.hpp" #include "../mwscript/scriptmanagerimp.hpp"
@ -36,9 +34,10 @@
#include "../mwworld/worldimp.hpp" #include "../mwworld/worldimp.hpp"
#include "LocalPlayer.hpp" #include "LocalPlayer.hpp"
#include "Main.hpp"
#include "Networking.hpp" #include "Networking.hpp"
#include "CellController.hpp" #include "CellController.hpp"
#include "Main.hpp" #include "MechanicsHelper.hpp"
using namespace mwmp; using namespace mwmp;
using namespace std; using namespace std;
@ -49,6 +48,8 @@ LocalPlayer::LocalPlayer()
charGenStage.end = 1; charGenStage.end = 1;
consoleAllowed = true; consoleAllowed = true;
ignorePosPacket = false; ignorePosPacket = false;
attack.shouldSend = false;
} }
LocalPlayer::~LocalPlayer() LocalPlayer::~LocalPlayer()
@ -71,7 +72,7 @@ void LocalPlayer::update()
updateCell(); updateCell();
updatePosition(); updatePosition();
updateAnimFlags(); updateAnimFlags();
updateAttackState(); updateAttack();
updateDeadState(); updateDeadState();
updateEquipment(); updateEquipment();
updateStatsDynamic(); updateStatsDynamic();
@ -514,32 +515,20 @@ void LocalPlayer::updateInventory(bool forceUpdate)
sendInventory(); sendInventory();
} }
void LocalPlayer::updateAttackState(bool forceUpdate) void LocalPlayer::updateAttack()
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); if (attack.shouldSend)
MWWorld::Ptr player = getPlayerPtr();
using namespace MWMechanics;
static bool attackPressed = false; // prevent flood
MWMechanics::DrawState_ state = player.getClass().getNpcStats(player).getDrawState();
if (world->getPlayer().getAttackingOrSpell() && !attackPressed)
{ {
MWWorld::Ptr weapon = MWWorld::Ptr(); // hand-to-hand if (attack.type == Attack::MAGIC)
if (state == MWMechanics::DrawState_Spell)
{ {
attack.type = Attack::MAGIC;
attack.pressed = true;
attack.spellId = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); attack.spellId = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
attack.success = mwmp::Main::get().getMechanicsHelper()->getSpellSuccess(attack.spellId, getPlayerPtr());
} }
attackPressed = true; getNetworking()->getPlayerPacket(ID_PLAYER_ATTACK)->setPlayer(this);
} getNetworking()->getPlayerPacket(ID_PLAYER_ATTACK)->Send();
else if (!world->getPlayer().getAttackingOrSpell() && attackPressed)
{ attack.shouldSend = false;
attackPressed = false;
} }
} }
@ -1108,17 +1097,6 @@ void LocalPlayer::sendJournalIndex(const std::string& quest, int index)
getNetworking()->getPlayerPacket(ID_PLAYER_JOURNAL)->Send(); getNetworking()->getPlayerPacket(ID_PLAYER_JOURNAL)->Send();
} }
void LocalPlayer::sendAttack(Attack::TYPE type)
{
MWMechanics::DrawState_ state = getPlayerPtr().getClass().getNpcStats(getPlayerPtr()).getDrawState();
attack.type = type;
attack.pressed = false;
getNetworking()->getPlayerPacket(ID_PLAYER_ATTACK)->setPlayer(this);
getNetworking()->getPlayerPacket(ID_PLAYER_ATTACK)->Send();
}
void LocalPlayer::clearCellStates() void LocalPlayer::clearCellStates()
{ {
cellStateChanges.cellStates.clear(); cellStateChanges.cellStates.clear();
@ -1161,31 +1139,3 @@ void LocalPlayer::storeCurrentContainer(const MWWorld::Ptr &container, bool loot
currentContainer.mpNum = container.getCellRef().getMpNum(); currentContainer.mpNum = container.getCellRef().getMpNum();
currentContainer.loot = loot; currentContainer.loot = loot;
} }
void LocalPlayer::prepareAttack(Attack::TYPE type, bool state)
{
if (attack.pressed == state && type != Attack::MAGIC)
return;
MWMechanics::DrawState_ dstate = getPlayerPtr().getClass().getNpcStats(getPlayerPtr()).getDrawState();
if (dstate == MWMechanics::DrawState_Spell)
{
attack.spellId = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
attack.success = Misc::Rng::roll0to99() < MWMechanics::getSpellSuccessChance(attack.spellId, getPlayerPtr());
state = true;
}
else
{
attack.success = false;
}
attack.pressed = state;
attack.type = type;
attack.knockdown = false;
attack.block = false;
attack.target.guid = RakNet::RakNetGUID();
getNetworking()->getPlayerPacket(ID_PLAYER_ATTACK)->setPlayer(this);
getNetworking()->getPlayerPacket(ID_PLAYER_ATTACK)->Send();
}

View file

@ -34,7 +34,7 @@ namespace mwmp
void updateChar(); void updateChar();
void updateEquipment(bool forceUpdate = false); void updateEquipment(bool forceUpdate = false);
void updateInventory(bool forceUpdate = false); void updateInventory(bool forceUpdate = false);
void updateAttackState(bool forceUpdate = false); void updateAttack();
void updateDeadState(bool forceUpdate = false); void updateDeadState(bool forceUpdate = false);
void updateAnimFlags(bool forceUpdate = false); void updateAnimFlags(bool forceUpdate = false);
@ -66,7 +66,6 @@ namespace mwmp
void sendSpellRemoval(const ESM::Spell &spell); void sendSpellRemoval(const ESM::Spell &spell);
void sendJournalEntry(const std::string& id, int index, const MWWorld::Ptr& actor); void sendJournalEntry(const std::string& id, int index, const MWWorld::Ptr& actor);
void sendJournalIndex(const std::string& id, int index); void sendJournalIndex(const std::string& id, int index);
void sendAttack(Attack::TYPE type);
void clearCellStates(); void clearCellStates();
void clearCurrentContainer(); void clearCurrentContainer();
@ -74,8 +73,6 @@ namespace mwmp
void storeCellState(ESM::Cell cell, int stateType); void storeCellState(ESM::Cell cell, int stateType);
void storeCurrentContainer(const MWWorld::Ptr& container, bool loot); void storeCurrentContainer(const MWWorld::Ptr& container, bool loot);
void prepareAttack(Attack::TYPE type, bool state);
private: private:
Networking *getNetworking(); Networking *getNetworking();
MWWorld::Ptr getPlayerPtr(); MWWorld::Ptr getPlayerPtr();

View file

@ -97,10 +97,14 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
{ {
if (attack.pressed == false) if (attack.pressed == false)
{ {
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Attack success: %s", attack.success ? "true" : "false"); LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Processing attack from %s",
attacker.getCellRef().getRefId().c_str());
LOG_APPEND(Log::LOG_VERBOSE, "- success: %s", attack.success ? "true" : "false");
if (attack.success == true) if (attack.success == true)
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Damage: %f", attack.damage); {
LOG_APPEND(Log::LOG_VERBOSE, "- damage: %f", attack.damage);
}
} }
MWMechanics::CreatureStats &attackerStats = attacker.getClass().getNpcStats(attacker); MWMechanics::CreatureStats &attackerStats = attacker.getClass().getNpcStats(attacker);
@ -108,10 +112,33 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
MWWorld::Ptr victim; MWWorld::Ptr victim;
if (attack.target.refId.empty())
{
if (attack.target.guid == mwmp::Main::get().getLocalPlayer()->guid) if (attack.target.guid == mwmp::Main::get().getLocalPlayer()->guid)
{
victim = MWBase::Environment::get().getWorld()->getPlayerPtr(); victim = MWBase::Environment::get().getWorld()->getPlayerPtr();
else if (PlayerList::getPlayer(attack.target.guid) != 0) }
else if (PlayerList::getPlayer(attack.target.guid) != NULL)
{
victim = PlayerList::getPlayer(attack.target.guid)->getPtr(); victim = PlayerList::getPlayer(attack.target.guid)->getPtr();
}
}
else
{
if (mwmp::Main::get().getCellController()->isLocalActor(attack.target.refId,
attack.target.refNumIndex, attack.target.mpNum))
{
victim = mwmp::Main::get().getCellController()->getLocalActor(attack.target.refId,
attack.target.refNumIndex, attack.target.mpNum)->getPtr();
}
else if (mwmp::Main::get().getCellController()->isDedicatedActor(attack.target.refId,
attack.target.refNumIndex, attack.target.mpNum))
{
victim = mwmp::Main::get().getCellController()->getDedicatedActor(attack.target.refId,
attack.target.refNumIndex, attack.target.mpNum)->getPtr();
}
}
// Get the weapon used (if hand-to-hand, weapon = inv.end()) // Get the weapon used (if hand-to-hand, weapon = inv.end())
if (attackerStats.getDrawState() == MWMechanics::DrawState_Weapon) if (attackerStats.getDrawState() == MWMechanics::DrawState_Weapon)
@ -124,7 +151,7 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
if (!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) if (!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
weapon = MWWorld::Ptr(); weapon = MWWorld::Ptr();
if (victim.mRef != 0) if (victim.mRef != NULL)
{ {
bool healthdmg; bool healthdmg;
if (!weapon.isEmpty()) if (!weapon.isEmpty())