mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-28 15:17:46 +00:00
Merge pull request #516 from NotAdam/develop
diminishing aggro distance based on level, bnpc avoidance
This commit is contained in:
commit
6d69cefdfd
10 changed files with 120 additions and 29 deletions
|
@ -57,6 +57,11 @@ namespace Sapphire::Common
|
||||||
French = 8
|
French = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TellFlags : uint8_t
|
||||||
|
{
|
||||||
|
GmTellMsg = 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
enum ObjKind : uint8_t
|
enum ObjKind : uint8_t
|
||||||
{
|
{
|
||||||
None = 0x00,
|
None = 0x00,
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct FFXIVIpcTell : FFXIVIpcBasePacket< Tell >
|
||||||
{
|
{
|
||||||
uint64_t contentId;
|
uint64_t contentId;
|
||||||
uint16_t worldId;
|
uint16_t worldId;
|
||||||
uint8_t preName;
|
uint8_t flags;
|
||||||
char receipientName[32];
|
char receipientName[32];
|
||||||
char msg[1029];
|
char msg[1029];
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,18 +57,22 @@ Sapphire::Common::FFXIVARR_POSITION3& Sapphire::Entity::Actor::getPos()
|
||||||
return m_pos;
|
return m_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Actor::setPos( float x, float y, float z )
|
void Sapphire::Entity::Actor::setPos( float x, float y, float z, bool broadcastUpdate )
|
||||||
{
|
{
|
||||||
m_pos.x = x;
|
m_pos.x = x;
|
||||||
m_pos.y = y;
|
m_pos.y = y;
|
||||||
m_pos.z = z;
|
m_pos.z = z;
|
||||||
m_pCurrentZone->updateActorPosition( *this );
|
|
||||||
|
if( broadcastUpdate )
|
||||||
|
m_pCurrentZone->updateActorPosition( *this );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Actor::setPos( const Sapphire::Common::FFXIVARR_POSITION3& pos )
|
void Sapphire::Entity::Actor::setPos( const Sapphire::Common::FFXIVARR_POSITION3& pos, bool broadcastUpdate )
|
||||||
{
|
{
|
||||||
m_pos = pos;
|
m_pos = pos;
|
||||||
m_pCurrentZone->updateActorPosition( *this );
|
|
||||||
|
if( broadcastUpdate )
|
||||||
|
m_pCurrentZone->updateActorPosition( *this );
|
||||||
}
|
}
|
||||||
|
|
||||||
float Sapphire::Entity::Actor::getRot() const
|
float Sapphire::Entity::Actor::getRot() const
|
||||||
|
|
|
@ -59,9 +59,9 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
Common::FFXIVARR_POSITION3& getPos();
|
Common::FFXIVARR_POSITION3& getPos();
|
||||||
|
|
||||||
void setPos( const Common::FFXIVARR_POSITION3& pos );
|
void setPos( const Common::FFXIVARR_POSITION3& pos, bool broadcastUpdate = true );
|
||||||
|
|
||||||
void setPos( float x, float y, float z );
|
void setPos( float x, float y, float z, bool broadcastUpdate = true );
|
||||||
|
|
||||||
float getRot() const;
|
float getRot() const;
|
||||||
|
|
||||||
|
|
|
@ -90,18 +90,35 @@ Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX
|
||||||
memcpy( m_customize, pTemplate->getCustomize(), sizeof( m_customize ) );
|
memcpy( m_customize, pTemplate->getCustomize(), sizeof( m_customize ) );
|
||||||
memcpy( m_modelEquip, pTemplate->getModelEquip(), sizeof( m_modelEquip ) );
|
memcpy( m_modelEquip, pTemplate->getModelEquip(), sizeof( m_modelEquip ) );
|
||||||
|
|
||||||
m_lastTickTime = 0;
|
auto exdData = m_pFw->get< Data::ExdDataGenerated >();
|
||||||
|
assert( exdData );
|
||||||
|
|
||||||
|
auto bNpcBaseData = exdData->get< Data::BNpcBase >( m_bNpcBaseId );
|
||||||
|
assert( bNpcBaseData );
|
||||||
|
|
||||||
|
m_scale = bNpcBaseData->scale;
|
||||||
|
|
||||||
|
// todo: is this actually good?
|
||||||
|
m_naviTargetReachedDistance = m_scale * 2.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sapphire::Entity::BNpc::~BNpc()
|
Sapphire::Entity::BNpc::~BNpc() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t Sapphire::Entity::BNpc::getAggressionMode() const
|
uint8_t Sapphire::Entity::BNpc::getAggressionMode() const
|
||||||
{
|
{
|
||||||
return m_aggressionMode;
|
return m_aggressionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Sapphire::Entity::BNpc::getNaviTargetReachedDistance() const
|
||||||
|
{
|
||||||
|
return m_naviTargetReachedDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Sapphire::Entity::BNpc::getScale() const
|
||||||
|
{
|
||||||
|
return m_scale;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t Sapphire::Entity::BNpc::getEnemyType() const
|
uint8_t Sapphire::Entity::BNpc::getEnemyType() const
|
||||||
{
|
{
|
||||||
return m_enemyType;
|
return m_enemyType;
|
||||||
|
@ -145,7 +162,7 @@ void Sapphire::Entity::BNpc::spawn( PlayerPtr pTarget )
|
||||||
void Sapphire::Entity::BNpc::despawn( PlayerPtr pTarget )
|
void Sapphire::Entity::BNpc::despawn( PlayerPtr pTarget )
|
||||||
{
|
{
|
||||||
pTarget->freePlayerSpawnId( getId() );
|
pTarget->freePlayerSpawnId( getId() );
|
||||||
pTarget->queuePacket( makeActorControl143( m_id, DespawnZoneScreenMsg, 0x04, getId(), 0x01 ) );
|
pTarget->queuePacket( makeActorControl143( m_id, DespawnZoneScreenMsg, 0x04, getId(), 0x01 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
Sapphire::Entity::BNpcState Sapphire::Entity::BNpc::getState() const
|
Sapphire::Entity::BNpcState Sapphire::Entity::BNpc::getState() const
|
||||||
|
@ -203,7 +220,11 @@ void Sapphire::Entity::BNpc::step()
|
||||||
|
|
||||||
bool Sapphire::Entity::BNpc::moveTo( const FFXIVARR_POSITION3& pos )
|
bool Sapphire::Entity::BNpc::moveTo( const FFXIVARR_POSITION3& pos )
|
||||||
{
|
{
|
||||||
if( Util::distance( getPos(), pos ) <= 4 )
|
// do this first, this will update local actor position and the position of other actors
|
||||||
|
// and then this npc will then path from the position after pushing/being pushed
|
||||||
|
pushNearbyBNpcs();
|
||||||
|
|
||||||
|
if( Util::distance( getPos(), pos ) <= m_naviTargetReachedDistance )
|
||||||
{
|
{
|
||||||
// Reached destination
|
// Reached destination
|
||||||
m_naviLastPath.clear();
|
m_naviLastPath.clear();
|
||||||
|
@ -402,7 +423,6 @@ void Sapphire::Entity::BNpc::onTick()
|
||||||
void Sapphire::Entity::BNpc::update( int64_t currTime )
|
void Sapphire::Entity::BNpc::update( int64_t currTime )
|
||||||
{
|
{
|
||||||
const uint8_t minActorDistance = 4;
|
const uint8_t minActorDistance = 4;
|
||||||
const uint8_t aggroRange = 8;
|
|
||||||
const uint8_t maxDistanceToOrigin = 40;
|
const uint8_t maxDistanceToOrigin = 40;
|
||||||
const uint32_t roamTick = 20;
|
const uint32_t roamTick = 20;
|
||||||
|
|
||||||
|
@ -441,7 +461,7 @@ void Sapphire::Entity::BNpc::update( int64_t currTime )
|
||||||
m_state = BNpcState::Idle;
|
m_state = BNpcState::Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAggro( aggroRange );
|
checkAggro();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -462,7 +482,7 @@ void Sapphire::Entity::BNpc::update( int64_t currTime )
|
||||||
m_state = BNpcState::Roaming;
|
m_state = BNpcState::Roaming;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAggro( aggroRange );
|
checkAggro();
|
||||||
}
|
}
|
||||||
|
|
||||||
case BNpcState::Combat:
|
case BNpcState::Combat:
|
||||||
|
@ -574,7 +594,7 @@ void Sapphire::Entity::BNpc::setTimeOfDeath( uint32_t timeOfDeath )
|
||||||
m_timeOfDeath = timeOfDeath;
|
m_timeOfDeath = timeOfDeath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::checkAggro( uint32_t range )
|
void Sapphire::Entity::BNpc::checkAggro()
|
||||||
{
|
{
|
||||||
// passive mobs should ignore players unless aggro'd
|
// passive mobs should ignore players unless aggro'd
|
||||||
if( m_aggressionMode == 1 )
|
if( m_aggressionMode == 1 )
|
||||||
|
@ -582,14 +602,61 @@ void Sapphire::Entity::BNpc::checkAggro( uint32_t range )
|
||||||
|
|
||||||
CharaPtr pClosestChara = getClosestChara();
|
CharaPtr pClosestChara = getClosestChara();
|
||||||
|
|
||||||
if( pClosestChara && pClosestChara->isAlive() )
|
if( pClosestChara && pClosestChara->isAlive() && pClosestChara->isPlayer() )
|
||||||
{
|
{
|
||||||
|
// will use this range if chara level is lower than bnpc, otherwise diminishing equation applies
|
||||||
|
float range = 13.f;
|
||||||
|
|
||||||
|
if( pClosestChara->getLevel() > m_level )
|
||||||
|
{
|
||||||
|
auto levelDiff = std::abs( pClosestChara->getLevel() - this->getLevel() );
|
||||||
|
|
||||||
|
if( levelDiff >= 10 )
|
||||||
|
range = 0.f;
|
||||||
|
else
|
||||||
|
range = std::max< float >( 0.f, range - std::pow( 1.53f, levelDiff * 0.6f ) );
|
||||||
|
}
|
||||||
|
|
||||||
auto distance = Util::distance( getPos().x, getPos().y, getPos().z,
|
auto distance = Util::distance( getPos().x, getPos().y, getPos().z,
|
||||||
pClosestChara->getPos().x,
|
pClosestChara->getPos().x,
|
||||||
pClosestChara->getPos().y,
|
pClosestChara->getPos().y,
|
||||||
pClosestChara->getPos().z );
|
pClosestChara->getPos().z );
|
||||||
|
|
||||||
if( distance < range && pClosestChara->isPlayer() )
|
if( distance < range )
|
||||||
|
{
|
||||||
aggro( pClosestChara );
|
aggro( pClosestChara );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::BNpc::pushNearbyBNpcs()
|
||||||
|
{
|
||||||
|
for( auto& bNpc : m_inRangeBNpc )
|
||||||
|
{
|
||||||
|
auto pos = bNpc->getPos();
|
||||||
|
auto distance = Util::distance( m_pos, bNpc->getPos() );
|
||||||
|
|
||||||
|
// todo: not sure what's good here
|
||||||
|
auto factor = bNpc->getNaviTargetReachedDistance();
|
||||||
|
|
||||||
|
auto delta = static_cast< float >( Util::getTimeMs() - bNpc->getLastUpdateTime() ) / 1000.f;
|
||||||
|
delta = std::min< float >( factor, delta );
|
||||||
|
|
||||||
|
// too far away, ignore it
|
||||||
|
if( distance > factor )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto angle = Util::calcAngFrom( m_pos.x, m_pos.y, pos.x, pos.y ) + PI;
|
||||||
|
|
||||||
|
auto x = ( cosf( angle ) );
|
||||||
|
auto z = ( sinf( angle ) );
|
||||||
|
|
||||||
|
bNpc->setPos( pos.x + ( x * factor * delta ),
|
||||||
|
pos.y,
|
||||||
|
pos.z + ( z * factor * delta ), false );
|
||||||
|
|
||||||
|
// setPos( m_pos.x + ( xBase * -pushDistance ),
|
||||||
|
// m_pos.y,
|
||||||
|
// m_pos.z + ( zBase * -pushDistance ) );
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,6 +60,9 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
uint8_t getAggressionMode() const;
|
uint8_t getAggressionMode() const;
|
||||||
|
|
||||||
|
float getScale() const;
|
||||||
|
float getNaviTargetReachedDistance() const;
|
||||||
|
|
||||||
// return true if it reached the position
|
// return true if it reached the position
|
||||||
bool moveTo( const Common::FFXIVARR_POSITION3& pos );
|
bool moveTo( const Common::FFXIVARR_POSITION3& pos );
|
||||||
|
|
||||||
|
@ -93,7 +96,9 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
void regainHp();
|
void regainHp();
|
||||||
|
|
||||||
void checkAggro( uint32_t range );
|
void checkAggro();
|
||||||
|
|
||||||
|
void pushNearbyBNpcs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_bNpcBaseId;
|
uint32_t m_bNpcBaseId;
|
||||||
|
@ -108,6 +113,9 @@ namespace Sapphire::Entity
|
||||||
uint32_t m_displayFlags;
|
uint32_t m_displayFlags;
|
||||||
uint8_t m_level;
|
uint8_t m_level;
|
||||||
|
|
||||||
|
float m_scale;
|
||||||
|
float m_naviTargetReachedDistance;
|
||||||
|
|
||||||
uint32_t m_timeOfDeath;
|
uint32_t m_timeOfDeath;
|
||||||
uint32_t m_lastRoamTargetReached;
|
uint32_t m_lastRoamTargetReached;
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,10 @@ Sapphire::Entity::Chara::Chara( ObjKind type, FrameworkPtr pFw ) :
|
||||||
m_targetId( INVALID_GAME_OBJECT_ID64 ),
|
m_targetId( INVALID_GAME_OBJECT_ID64 ),
|
||||||
m_pFw( std::move( std::move( pFw ) ) )
|
m_pFw( std::move( std::move( pFw ) ) )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
m_lastTickTime = 0;
|
||||||
|
m_lastUpdate = 0;
|
||||||
|
|
||||||
// initialize the free slot queue
|
// initialize the free slot queue
|
||||||
for( uint8_t i = 0; i < MAX_STATUS_EFFECTS; i++ )
|
for( uint8_t i = 0; i < MAX_STATUS_EFFECTS; i++ )
|
||||||
{
|
{
|
||||||
|
@ -791,3 +795,7 @@ bool Sapphire::Entity::Chara::hasStatusEffect( uint32_t id )
|
||||||
return m_statusEffectMap.find( id ) != m_statusEffectMap.end();
|
return m_statusEffectMap.find( id ) != m_statusEffectMap.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t Sapphire::Entity::Chara::getLastUpdateTime() const
|
||||||
|
{
|
||||||
|
return m_lastUpdate;
|
||||||
|
}
|
||||||
|
|
|
@ -118,6 +118,8 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
virtual void calculateStats() {};
|
virtual void calculateStats() {};
|
||||||
|
|
||||||
|
int64_t getLastUpdateTime() const;
|
||||||
|
|
||||||
/// Status effect functions
|
/// Status effect functions
|
||||||
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
||||||
|
|
||||||
|
|
|
@ -636,14 +636,14 @@ void Sapphire::Network::GameConnection::tellHandler( FrameworkPtr pFw,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty ) )
|
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty ) && !player.isActingAsGm() )
|
||||||
{
|
{
|
||||||
// send error for player bound by duty
|
// send error for player bound by duty
|
||||||
// TODO: implement me
|
// TODO: implement me
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pTargetPlayer->getOnlineStatus() == OnlineStatus::Busy )
|
if( pTargetPlayer->getOnlineStatus() == OnlineStatus::Busy && !player.isActingAsGm() )
|
||||||
{
|
{
|
||||||
// send error for player being busy
|
// send error for player being busy
|
||||||
// TODO: implement me ( i've seen this done with packet type 67 i think )
|
// TODO: implement me ( i've seen this done with packet type 67 i think )
|
||||||
|
@ -656,16 +656,13 @@ void Sapphire::Network::GameConnection::tellHandler( FrameworkPtr pFw,
|
||||||
// TODO: world id from server
|
// TODO: world id from server
|
||||||
tellPacket->data().contentId = player.getContentId();
|
tellPacket->data().contentId = player.getContentId();
|
||||||
tellPacket->data().worldId = 67;
|
tellPacket->data().worldId = 67;
|
||||||
// TODO: do these have a meaning?
|
|
||||||
//tellPacket.data().u1 = 0x92CD7337;
|
|
||||||
//tellPacket.data().u2a = 0x2E;
|
|
||||||
//tellPacket.data().u2b = 0x40;
|
|
||||||
if( player.isActingAsGm() )
|
if( player.isActingAsGm() )
|
||||||
{
|
{
|
||||||
tellPacket->data().preName = 0x04;
|
tellPacket->data().flags |= TellFlags::GmTellMsg;
|
||||||
}
|
}
|
||||||
pTargetPlayer->queueChatPacket( tellPacket );
|
|
||||||
|
|
||||||
|
pTargetPlayer->queueChatPacket( tellPacket );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Network::GameConnection::performNoteHandler( FrameworkPtr pFw,
|
void Sapphire::Network::GameConnection::performNoteHandler( FrameworkPtr pFw,
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace Sapphire
|
||||||
Common::Weather m_currentWeather;
|
Common::Weather m_currentWeather;
|
||||||
Common::Weather m_weatherOverride;
|
Common::Weather m_weatherOverride;
|
||||||
|
|
||||||
uint64_t m_lastMobUpdate;
|
int64_t m_lastMobUpdate;
|
||||||
|
|
||||||
FestivalPair m_currentFestival;
|
FestivalPair m_currentFestival;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue