1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-06-22 18:41:36 +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:
David Cernat 2018-09-11 11:56:45 +03:00
parent 31a9b77f34
commit fcd31bf4a6
5 changed files with 101 additions and 74 deletions

View file

@ -217,10 +217,18 @@ namespace MWMechanics
/* /*
Start of tes3mp addition 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; return;
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
if (localAttack)
localAttack->type = mwmp::Attack::RANGED;
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -245,10 +253,10 @@ namespace MWMechanics
/* /*
Start of tes3mp addition 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()) if (localAttack)
mwmp::Main::get().getLocalPlayer()->attack.success = true; localAttack->success = true;
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -258,11 +266,10 @@ namespace MWMechanics
/* /*
Start of tes3mp addition Start of tes3mp addition
Mark this as a failed attack for LocalPlayer now that the hit roll Mark this as a failed LocalAttack now that the hit roll has failed
has failed
*/ */
if (attacker == getPlayer()) if (localAttack)
mwmp::Main::get().getLocalPlayer()->attack.success = false; localAttack->success = false;
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -312,8 +319,6 @@ namespace MWMechanics
Track whether the strike enchantment is successful for attacks by the Track whether the strike enchantment is successful for attacks by the
LocalPlayer or LocalActors for both their weapon and projectile LocalPlayer or LocalActors for both their weapon and projectile
*/ */
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition, true); bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition, true);
if (localAttack) if (localAttack)
@ -342,6 +347,19 @@ namespace MWMechanics
victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true); 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) float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue)

View file

@ -204,14 +204,16 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
{ {
if (!attack.pressed) if (!attack.pressed)
{ {
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Processing attack from %s", LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Processing attack from %s of type %i",
attacker.getCellRef().getRefId().c_str()); attacker.getCellRef().getRefId().c_str(), attack.type);
LOG_APPEND(Log::LOG_VERBOSE, "- success: %s", attack.success ? "true" : "false"); LOG_APPEND(Log::LOG_VERBOSE, "- success: %s", attack.success ? "true" : "false");
if (attack.success) if (attack.success)
LOG_APPEND(Log::LOG_VERBOSE, "- damage: %f", attack.damage); 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); MWMechanics::CreatureStats &attackerStats = attacker.getClass().getCreatureStats(attacker);
MWWorld::Ptr victim; 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(); 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 || attack.type == attack.RANGED)
if (attack.type == attack.MELEE)
{ {
bool isRanged = attack.type == attack.RANGED;
MWWorld::Ptr weapon; MWWorld::Ptr weapon;
MWWorld::Ptr projectile; MWWorld::Ptr projectile;
// Get the weapon used; if using hand-to-hand, the weapon is equal to inv.end()
if (attacker.getClass().hasInventoryStore(attacker)) if (attacker.getClass().hasInventoryStore(attacker))
{ {
MWWorld::InventoryStore &inventoryStore = attacker.getClass().getInventoryStore(attacker); MWWorld::InventoryStore &inventoryStore = attacker.getClass().getInventoryStore(attacker);
@ -253,40 +257,44 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
weapon = MWWorld::Ptr(); 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) if (victim.mRef != nullptr)
{ {
bool healthdmg = true; if (!isRanged)
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());
MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1); MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1);
if (attack.applyWeaponEnchantment) victim.getClass().onHit(victim, attack.damage, isHealthDamage, weapon, attacker, attack.hitPosition.asVec3(),
{
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(),
attack.success); attack.success);
} }
} }
@ -300,7 +308,7 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
attack.instant = false; 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) else if (attack.type == attack.ITEM_MAGIC)
{ {

View file

@ -69,6 +69,7 @@ namespace mwmp
enum TYPE enum TYPE
{ {
MELEE = 0, MELEE = 0,
RANGED,
MAGIC, MAGIC,
ITEM_MAGIC, ITEM_MAGIC,
THROWABLE THROWABLE

View file

@ -26,19 +26,19 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send)
RW(actor.attack.type, 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.pressed, send);
RW(actor.attack.success, 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.instant, send);
RW(actor.attack.hitPosition.pos[1], send); RW(actor.attack.spellId, send, true);
RW(actor.attack.hitPosition.pos[2], send);
} }
else
if (actor.attack.type == mwmp::Attack::MELEE)
{ {
RW(actor.attack.damage, send); RW(actor.attack.damage, send);
RW(actor.attack.block, 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.applyWeaponEnchantment, send);
RW(actor.attack.applyProjectileEnchantment, send); RW(actor.attack.applyProjectileEnchantment, send);
}
else if (actor.attack.type == mwmp::Attack::MAGIC) if (actor.attack.success || actor.attack.applyWeaponEnchantment || actor.attack.applyProjectileEnchantment)
{ {
RW(actor.attack.instant, send); RW(actor.attack.hitPosition.pos[0], send);
RW(actor.attack.spellId, send, true); 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);
} }

View file

@ -27,19 +27,19 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send)
RW(player->attack.type, 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.pressed, send);
RW(player->attack.success, 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.instant, send);
RW(player->attack.hitPosition.pos[1], send); RW(player->attack.spellId, send, true);
RW(player->attack.hitPosition.pos[2], send);
} }
else
if (player->attack.type == mwmp::Attack::MELEE)
{ {
RW(player->attack.damage, send); RW(player->attack.damage, send);
RW(player->attack.block, 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.applyWeaponEnchantment, send);
RW(player->attack.applyProjectileEnchantment, send); RW(player->attack.applyProjectileEnchantment, send);
}
else if (player->attack.type == mwmp::Attack::MAGIC) if (player->attack.success || player->attack.applyWeaponEnchantment || player->attack.applyProjectileEnchantment)
{ {
RW(player->attack.instant, send); RW(player->attack.hitPosition.pos[0], send);
RW(player->attack.spellId, send, true); 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);
} }