1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-26 22:37:45 +00:00

Merge pull request #747 from hkAlice/slippin-fallin-cant-get-up

[3.0] fall damage implementation;
This commit is contained in:
Mordred 2022-01-06 00:59:57 +01:00 committed by GitHub
commit 67d3d28a75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 13 deletions

View file

@ -2153,6 +2153,64 @@ Sapphire::Entity::Player::FriendListIDVec& Sapphire::Entity::Player::getBlacklis
return m_blacklist; return m_blacklist;
} }
void Sapphire::Entity::Player::setFalling( bool state, const Common::FFXIVARR_POSITION3& pos, bool ignoreDamage )
{
bool isFalling = m_falling;
auto initialPos = m_initialFallPos;
// update internal values - only use scoped values for old state
m_falling = state;
m_initialFallPos = pos;
if( ignoreDamage )
return;
// if the player is currently falling and new state is grounded - calc and apply fall dmg
if( isFalling && !state )
{
// calc height difference
auto fallHeight = initialPos.y - pos.y;
// if we've hit the breakpoint in fall damage (min: 10y)
if( fallHeight >= 10.f )
{
// calculate how much damage to deal out (max. 20y : 100%)
float deltaMax = std::min( fallHeight, 20.f );
// get hp percentage starting from 0.1, increasing to 100% at max height
float hpPer = std::min( 0.1f + ( deltaMax - 10.f ) / 10.f, 1.f );
uint32_t damage = getMaxHp() * hpPer;
// check if player has aggro - if not, player should "live"
if( m_actorIdTohateSlotMap.empty() )
{
// "trick" client into thinking we took more damage than internally passed to takeDamage, if > playerHp
uint32_t surviveDamage = damage;
if( surviveDamage >= getHp() )
{
surviveDamage = ( getHp() - 1 );
}
takeDamage( surviveDamage );
}
else
{
// no mercy on hated players
takeDamage( damage );
}
sendToInRangeSet( makeActorControl( getId(), DmgTakenMsg, damage ), true );
}
}
}
bool Sapphire::Entity::Player::isFalling() const
{
return m_falling;
}
void Sapphire::Entity::Player::setLastPcSearchResult( std::vector< uint32_t > result ) void Sapphire::Entity::Player::setLastPcSearchResult( std::vector< uint32_t > result )
{ {
m_lastPcSearch = std::move( result ); m_lastPcSearch = std::move( result );

View file

@ -821,7 +821,9 @@ namespace Sapphire::Entity
uint64_t m_lastMoveTime{}; uint64_t m_lastMoveTime{};
uint8_t m_lastMoveflag{}; uint8_t m_lastMoveflag{};
bool m_falling;
void setFalling( bool state, const Common::FFXIVARR_POSITION3& pos, bool ignoreDamage = false );
bool isFalling() const;
// todo: sort this requestkey pcsearch mess // todo: sort this requestkey pcsearch mess
void setLastPcSearchResult( std::vector< uint32_t > result ); void setLastPcSearchResult( std::vector< uint32_t > result );
@ -844,6 +846,10 @@ namespace Sapphire::Entity
uint8_t m_mode{}; uint8_t m_mode{};
// falling logic
bool m_falling;
Common::FFXIVARR_POSITION3 m_initialFallPos{};
bool m_markedForRemoval; bool m_markedForRemoval;
bool m_directorInitialized; bool m_directorInitialized;

View file

@ -232,13 +232,10 @@ void Sapphire::Network::GameConnection::moveHandler( const Packets::FFXIVARR_PAC
if( ( player.getCurrentAction() != nullptr ) && bPosChanged ) if( ( player.getCurrentAction() != nullptr ) && bPosChanged )
player.getCurrentAction()->setInterrupted( Common::ActionInterruptType::RegularInterrupt ); player.getCurrentAction()->setInterrupted( Common::ActionInterruptType::RegularInterrupt );
// if no one is in range, don't bother trying to send a position update
if( !player.hasInRangeActor() )
return;
auto clientAnimationType = data.flag; auto clientAnimationType = data.flag;
auto animationState = data.flag; auto animationState = data.flag;
auto animationType = data.flag2; auto animationType = data.flag2;
auto animColType = data.flag2;
auto headRotation = data.flag_unshared; auto headRotation = data.flag_unshared;
uint8_t orgAnimationType = animationType; uint8_t orgAnimationType = animationType;
uint8_t unknownRotation = 0; uint8_t unknownRotation = 0;
@ -262,34 +259,42 @@ void Sapphire::Network::GameConnection::moveHandler( const Packets::FFXIVARR_PAC
} }
if( animationType & MoveType::Jumping ) if( animationType & MoveType::Jumping )
{ {
if( animationState == MoveState::LeaveCollision )
if( animColType == MoveState::LeaveCollision )
{ {
if( orgAnimationType & clientAnimationType ) if( orgAnimationType & clientAnimationType )
animationType += 0x10; animationType += 0x10;
else else
animationType += 0x04; animationType += 0x04;
} }
if( animationState == MoveState::StartFalling )
player.m_falling = true; if( animColType == MoveState::LeaveCollision || animColType == MoveState::StartFalling )
if( animationState == MoveState::EnterCollision )
{ {
animationType = 2; player.setFalling( true, { data.pos.x, data.pos.y, data.pos.z } );
player.m_falling = false;
} }
} }
if( player.m_falling ) if( animColType == MoveState::EnterCollision )
{
animationType = 2;
player.setFalling( false, { data.pos.x, data.pos.y, data.pos.z } );
}
if( player.isFalling() )
{ {
animationType += 0x10; animationType += 0x10;
unknownRotation = 0x7F; unknownRotation = 0x7F;
} }
uint64_t currentTime = Util::getTimeMs(); uint64_t currentTime = Util::getTimeMs();
player.m_lastMoveTime = currentTime; player.m_lastMoveTime = currentTime;
player.m_lastMoveflag = animationType; player.m_lastMoveflag = animationType;
// if no one is in range, don't bother trying to send a position update
if( !player.hasInRangeActor() )
return;
//auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, animationType, animationState, animationSpeed, unknownRotation ); //auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, animationType, animationState, animationSpeed, unknownRotation );
auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, data.flag, data.flag2, animationSpeed, unknownRotation ); auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, data.flag, data.flag2, animationSpeed, unknownRotation );
player.sendToInRangeSet( movePacket ); player.sendToInRangeSet( movePacket );