mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-06 02:45:31 +00:00
[General] Fix problems with the synchronization of ranged attacks
Projectile hits now send Attack packets with RANGED attacks, and their success or failure is now synchronized. Strike enchantments no longer require a valid victim to be synchronized. Additional debug messages have been added for attacks.
This commit is contained in:
parent
31a9b77f34
commit
fcd31bf4a6
5 changed files with 101 additions and 74 deletions
|
@ -217,10 +217,18 @@ namespace MWMechanics
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Ignore projectiles fired by DedicatedPlayers
|
||||
Ignore projectiles fired by DedicatedPlayers and DedicatedActors
|
||||
|
||||
If fired by LocalPlayers and LocalActors, get the associated LocalAttack and set its type
|
||||
to RANGED
|
||||
*/
|
||||
if (mwmp::PlayerList::isDedicatedPlayer(attacker))
|
||||
if (mwmp::PlayerList::isDedicatedPlayer(attacker) || mwmp::Main::get().getCellController()->isDedicatedActor(attacker))
|
||||
return;
|
||||
|
||||
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
|
||||
|
||||
if (localAttack)
|
||||
localAttack->type = mwmp::Attack::RANGED;
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
@ -245,10 +253,10 @@ namespace MWMechanics
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Mark this as a successful attack for LocalPlayer unless proven otherwise
|
||||
Mark this as a successful attack for the associated LocalAttack unless proven otherwise
|
||||
*/
|
||||
if (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
mwmp::Main::get().getLocalPlayer()->attack.success = true;
|
||||
if (localAttack)
|
||||
localAttack->success = true;
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
@ -258,11 +266,10 @@ namespace MWMechanics
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Mark this as a failed attack for LocalPlayer now that the hit roll
|
||||
has failed
|
||||
Mark this as a failed LocalAttack now that the hit roll has failed
|
||||
*/
|
||||
if (attacker == getPlayer())
|
||||
mwmp::Main::get().getLocalPlayer()->attack.success = false;
|
||||
if (localAttack)
|
||||
localAttack->success = false;
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
@ -312,8 +319,6 @@ namespace MWMechanics
|
|||
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)
|
||||
|
@ -342,6 +347,19 @@ namespace MWMechanics
|
|||
|
||||
victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true);
|
||||
}
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If this is a local attack that had no victim, send a packet for it here
|
||||
*/
|
||||
else if (localAttack)
|
||||
{
|
||||
localAttack->hitPosition = MechanicsHelper::getPositionFromVector(hitPosition);
|
||||
localAttack->shouldSend = true;
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue)
|
||||
|
|
|
@ -204,14 +204,16 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
|||
{
|
||||
if (!attack.pressed)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Processing attack from %s",
|
||||
attacker.getCellRef().getRefId().c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Processing attack from %s of type %i",
|
||||
attacker.getCellRef().getRefId().c_str(), attack.type);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- success: %s", attack.success ? "true" : "false");
|
||||
|
||||
if (attack.success)
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- damage: %f", attack.damage);
|
||||
}
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- pressed: %s", attack.pressed ? "true" : "false");
|
||||
|
||||
MWMechanics::CreatureStats &attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||
MWWorld::Ptr victim;
|
||||
|
||||
|
@ -231,12 +233,14 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
|||
victim = controller->getDedicatedActor(attack.target.refNum, attack.target.mpNum)->getPtr();
|
||||
}
|
||||
|
||||
// Get the weapon used (if hand-to-hand, weapon = inv.end())
|
||||
if (attack.type == attack.MELEE)
|
||||
if (attack.type == attack.MELEE || attack.type == attack.RANGED)
|
||||
{
|
||||
bool isRanged = attack.type == attack.RANGED;
|
||||
|
||||
MWWorld::Ptr weapon;
|
||||
MWWorld::Ptr projectile;
|
||||
|
||||
// Get the weapon used; if using hand-to-hand, the weapon is equal to inv.end()
|
||||
if (attacker.getClass().hasInventoryStore(attacker))
|
||||
{
|
||||
MWWorld::InventoryStore &inventoryStore = attacker.getClass().getInventoryStore(attacker);
|
||||
|
@ -253,40 +257,44 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
|||
weapon = MWWorld::Ptr();
|
||||
}
|
||||
|
||||
bool isHealthDamage = true;
|
||||
|
||||
if (weapon.isEmpty())
|
||||
{
|
||||
if (attacker.getClass().isBipedal(attacker))
|
||||
{
|
||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||
isHealthDamage = otherstats.isParalyzed() || otherstats.getKnockedDown();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- weapon: %s\n- isRanged: %s\n- applyWeaponEnchantment: %s\n- applyProjectileEnchantment: %s",
|
||||
weapon.getCellRef().getRefId().c_str(), isRanged ? "true" : "false", attack.applyWeaponEnchantment ? "true" : "false",
|
||||
attack.applyProjectileEnchantment ? "true" : "false");
|
||||
|
||||
if (attack.applyWeaponEnchantment)
|
||||
{
|
||||
MWMechanics::CastSpell cast(attacker, victim, isRanged);
|
||||
cast.mHitPosition = attack.hitPosition.asVec3();
|
||||
|
||||
cast.cast(weapon, false);
|
||||
}
|
||||
|
||||
if (isRanged && !projectile.isEmpty() && attack.applyProjectileEnchantment)
|
||||
{
|
||||
MWMechanics::CastSpell cast(attacker, victim, isRanged);
|
||||
cast.mHitPosition = attack.hitPosition.asVec3();
|
||||
cast.cast(projectile, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (victim.mRef != nullptr)
|
||||
{
|
||||
bool healthdmg = true;
|
||||
|
||||
if (weapon.isEmpty())
|
||||
{
|
||||
if (attacker.getClass().isBipedal(attacker))
|
||||
{
|
||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||
healthdmg = otherstats.isParalyzed() || otherstats.getKnockedDown();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- weapon: %s", weapon.getCellRef().getRefId().c_str());
|
||||
|
||||
if (!isRanged)
|
||||
MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1);
|
||||
|
||||
if (attack.applyWeaponEnchantment)
|
||||
{
|
||||
MWMechanics::CastSpell cast(attacker, victim, false);
|
||||
cast.mHitPosition = attack.hitPosition.asVec3();
|
||||
cast.cast(weapon, false);
|
||||
}
|
||||
|
||||
if (attack.applyProjectileEnchantment)
|
||||
{
|
||||
MWMechanics::CastSpell cast(attacker, victim, false);
|
||||
cast.mHitPosition = attack.hitPosition.asVec3();
|
||||
cast.cast(projectile, false);
|
||||
}
|
||||
}
|
||||
|
||||
victim.getClass().onHit(victim, attack.damage, healthdmg, weapon, attacker, attack.hitPosition.asVec3(),
|
||||
victim.getClass().onHit(victim, attack.damage, isHealthDamage, weapon, attacker, attack.hitPosition.asVec3(),
|
||||
attack.success);
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +308,7 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
|||
attack.instant = false;
|
||||
}
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- spellId: %s, success: %s", attack.spellId.c_str(), attack.success ? "true" : "false");
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- spellId: %s", attack.spellId.c_str());
|
||||
}
|
||||
else if (attack.type == attack.ITEM_MAGIC)
|
||||
{
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace mwmp
|
|||
enum TYPE
|
||||
{
|
||||
MELEE = 0,
|
||||
RANGED,
|
||||
MAGIC,
|
||||
ITEM_MAGIC,
|
||||
THROWABLE
|
||||
|
|
|
@ -26,19 +26,19 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send)
|
|||
|
||||
RW(actor.attack.type, send);
|
||||
|
||||
if (actor.attack.type == mwmp::Attack::MELEE || actor.attack.type == mwmp::Attack::MAGIC)
|
||||
if (actor.attack.type == mwmp::Attack::ITEM_MAGIC)
|
||||
RW(actor.attack.itemId, send, true);
|
||||
else
|
||||
{
|
||||
RW(actor.attack.pressed, send);
|
||||
RW(actor.attack.success, send);
|
||||
|
||||
if (actor.attack.success)
|
||||
if (actor.attack.type == mwmp::Attack::MAGIC)
|
||||
{
|
||||
RW(actor.attack.hitPosition.pos[0], send);
|
||||
RW(actor.attack.hitPosition.pos[1], send);
|
||||
RW(actor.attack.hitPosition.pos[2], send);
|
||||
RW(actor.attack.instant, send);
|
||||
RW(actor.attack.spellId, send, true);
|
||||
}
|
||||
|
||||
if (actor.attack.type == mwmp::Attack::MELEE)
|
||||
else
|
||||
{
|
||||
RW(actor.attack.damage, send);
|
||||
RW(actor.attack.block, send);
|
||||
|
@ -46,13 +46,13 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send)
|
|||
|
||||
RW(actor.attack.applyWeaponEnchantment, send);
|
||||
RW(actor.attack.applyProjectileEnchantment, send);
|
||||
}
|
||||
else if (actor.attack.type == mwmp::Attack::MAGIC)
|
||||
{
|
||||
RW(actor.attack.instant, send);
|
||||
RW(actor.attack.spellId, send, true);
|
||||
|
||||
if (actor.attack.success || actor.attack.applyWeaponEnchantment || actor.attack.applyProjectileEnchantment)
|
||||
{
|
||||
RW(actor.attack.hitPosition.pos[0], send);
|
||||
RW(actor.attack.hitPosition.pos[1], send);
|
||||
RW(actor.attack.hitPosition.pos[2], send);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (actor.attack.type == mwmp::Attack::ITEM_MAGIC)
|
||||
RW(actor.attack.itemId, send, true);
|
||||
}
|
||||
|
|
|
@ -27,19 +27,19 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send)
|
|||
|
||||
RW(player->attack.type, send);
|
||||
|
||||
if (player->attack.type == mwmp::Attack::MELEE || player->attack.type == mwmp::Attack::MAGIC)
|
||||
if (player->attack.type == mwmp::Attack::ITEM_MAGIC)
|
||||
RW(player->attack.itemId, send, true);
|
||||
else
|
||||
{
|
||||
RW(player->attack.pressed, send);
|
||||
RW(player->attack.success, send);
|
||||
|
||||
if (player->attack.success)
|
||||
if (player->attack.type == mwmp::Attack::MAGIC)
|
||||
{
|
||||
RW(player->attack.hitPosition.pos[0], send);
|
||||
RW(player->attack.hitPosition.pos[1], send);
|
||||
RW(player->attack.hitPosition.pos[2], send);
|
||||
RW(player->attack.instant, send);
|
||||
RW(player->attack.spellId, send, true);
|
||||
}
|
||||
|
||||
if (player->attack.type == mwmp::Attack::MELEE)
|
||||
else
|
||||
{
|
||||
RW(player->attack.damage, send);
|
||||
RW(player->attack.block, send);
|
||||
|
@ -47,13 +47,13 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send)
|
|||
|
||||
RW(player->attack.applyWeaponEnchantment, send);
|
||||
RW(player->attack.applyProjectileEnchantment, send);
|
||||
}
|
||||
else if (player->attack.type == mwmp::Attack::MAGIC)
|
||||
{
|
||||
RW(player->attack.instant, send);
|
||||
RW(player->attack.spellId, send, true);
|
||||
|
||||
if (player->attack.success || player->attack.applyWeaponEnchantment || player->attack.applyProjectileEnchantment)
|
||||
{
|
||||
RW(player->attack.hitPosition.pos[0], send);
|
||||
RW(player->attack.hitPosition.pos[1], send);
|
||||
RW(player->attack.hitPosition.pos[2], send);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (player->attack.type == mwmp::Attack::ITEM_MAGIC)
|
||||
RW(player->attack.itemId, send, true);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue