mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 06:47:45 +00:00
Merge pull request #747 from hkAlice/slippin-fallin-cant-get-up
[3.0] fall damage implementation;
This commit is contained in:
commit
67d3d28a75
3 changed files with 82 additions and 13 deletions
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
Loading…
Add table
Reference in a new issue