1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-26 14:37:44 +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;
}
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 )
{
m_lastPcSearch = std::move( result );

View file

@ -821,7 +821,9 @@ namespace Sapphire::Entity
uint64_t m_lastMoveTime{};
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
void setLastPcSearchResult( std::vector< uint32_t > result );
@ -844,6 +846,10 @@ namespace Sapphire::Entity
uint8_t m_mode{};
// falling logic
bool m_falling;
Common::FFXIVARR_POSITION3 m_initialFallPos{};
bool m_markedForRemoval;
bool m_directorInitialized;

View file

@ -232,13 +232,10 @@ void Sapphire::Network::GameConnection::moveHandler( const Packets::FFXIVARR_PAC
if( ( player.getCurrentAction() != nullptr ) && bPosChanged )
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 animationState = data.flag;
auto animationType = data.flag2;
auto animColType = data.flag2;
auto headRotation = data.flag_unshared;
uint8_t orgAnimationType = animationType;
uint8_t unknownRotation = 0;
@ -262,34 +259,42 @@ void Sapphire::Network::GameConnection::moveHandler( const Packets::FFXIVARR_PAC
}
if( animationType & MoveType::Jumping )
{
if( animationState == MoveState::LeaveCollision )
if( animColType == MoveState::LeaveCollision )
{
if( orgAnimationType & clientAnimationType )
animationType += 0x10;
else
animationType += 0x04;
}
if( animationState == MoveState::StartFalling )
player.m_falling = true;
if( animationState == MoveState::EnterCollision )
if( animColType == MoveState::LeaveCollision || animColType == MoveState::StartFalling )
{
animationType = 2;
player.m_falling = false;
player.setFalling( true, { data.pos.x, data.pos.y, data.pos.z } );
}
}
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;
unknownRotation = 0x7F;
}
uint64_t currentTime = Util::getTimeMs();
player.m_lastMoveTime = currentTime;
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, data.flag, data.flag2, animationSpeed, unknownRotation );
player.sendToInRangeSet( movePacket );