2017-08-08 13:53:47 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <vector>
|
2018-03-02 07:22:25 -03:00
|
|
|
#include <time.h>
|
2019-01-13 00:51:31 +01:00
|
|
|
#include <random>
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Logging/Logger.h>
|
|
|
|
#include <Util/Util.h>
|
|
|
|
#include <Util/UtilMath.h>
|
2019-03-08 15:34:38 +01:00
|
|
|
#include <Network/GamePacket.h>
|
2021-11-27 00:53:57 +01:00
|
|
|
#include <Exd/ExdData.h>
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Network/CommonNetwork.h>
|
|
|
|
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
|
|
|
#include <Network/PacketContainer.h>
|
2018-06-23 21:38:04 +02:00
|
|
|
#include <Network/CommonActorControl.h>
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Database/DatabaseDef.h>
|
2019-10-09 18:14:53 +02:00
|
|
|
#include <Network/PacketWrappers/ActorControlSelfPacket.h>
|
2020-02-29 22:30:10 +11:00
|
|
|
#include <Service.h>
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-07-21 22:33:33 +10:00
|
|
|
#include "Territory.h"
|
2018-02-23 23:47:21 +01:00
|
|
|
#include "InstanceContent.h"
|
2019-03-31 11:27:11 +02:00
|
|
|
#include "QuestBattle.h"
|
2018-12-01 00:27:16 +11:00
|
|
|
#include "Manager/TerritoryMgr.h"
|
2019-04-20 19:40:44 +10:00
|
|
|
#include "Navi/NaviProvider.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Session.h"
|
2018-02-20 22:46:44 +01:00
|
|
|
#include "Actor/Chara.h"
|
2021-11-27 00:53:57 +01:00
|
|
|
#include "Actor/GameObject.h"
|
2018-09-09 23:56:22 +02:00
|
|
|
#include "Actor/BNpc.h"
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Actor/Player.h"
|
2018-02-28 10:26:03 +01:00
|
|
|
#include "Actor/EventObject.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-07-27 13:59:35 +10:00
|
|
|
#include "Action/EffectResult.h"
|
|
|
|
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Network/GameConnection.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-03-02 07:22:25 -03:00
|
|
|
#include "Script/ScriptMgr.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-09-09 23:56:22 +02:00
|
|
|
#include "ForwardsZone.h"
|
2021-11-27 00:53:57 +01:00
|
|
|
#include "WorldServer.h"
|
2018-03-02 07:22:25 -03:00
|
|
|
#include "CellHandler.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-04-19 00:39:42 +02:00
|
|
|
#include "Manager/RNGMgr.h"
|
|
|
|
#include "Manager/NaviMgr.h"
|
2021-12-30 13:57:08 +01:00
|
|
|
#include "Math/CalcStats.h"
|
2019-01-19 21:20:23 -02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
using namespace Sapphire;
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Network::Packets;
|
2021-11-27 00:53:57 +01:00
|
|
|
using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Network::ActorControl;
|
2018-12-01 00:27:16 +11:00
|
|
|
using namespace Sapphire::World::Manager;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
#define START_EOBJ_ID 0x400D0000
|
|
|
|
#define START_GAMEOBJECT_ID 0x500D0000
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Territory::Territory() :
|
2018-11-05 23:07:39 +01:00
|
|
|
m_territoryTypeId( 0 ),
|
2022-02-16 15:11:10 -03:00
|
|
|
m_ident(),
|
2018-08-29 21:40:59 +02:00
|
|
|
m_guId( 0 ),
|
2022-02-05 23:31:35 +01:00
|
|
|
m_currentWeather( Common::Weather::FairSkies ),
|
|
|
|
m_weatherOverride( Common::Weather::None ),
|
2018-08-29 21:40:59 +02:00
|
|
|
m_lastMobUpdate( 0 ),
|
2021-11-27 00:53:57 +01:00
|
|
|
m_nextEObjId( START_EOBJ_ID ),
|
|
|
|
m_nextActorId( START_GAMEOBJECT_ID )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Territory::Territory( uint16_t territoryTypeId, uint32_t guId, const std::string& internalName, const std::string& placeName ) :
|
|
|
|
m_currentWeather( Common::Weather::FairSkies ),
|
2021-11-27 00:53:57 +01:00
|
|
|
m_nextEObjId( START_EOBJ_ID ),
|
|
|
|
m_nextActorId( START_GAMEOBJECT_ID ),
|
2019-04-07 16:01:53 +02:00
|
|
|
m_lastUpdate( 0 ),
|
2022-02-05 23:31:35 +01:00
|
|
|
m_lastActivityTime( Common::Util::getTimeMs() )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& exdData = Common::Service< Data::ExdData >::ref();
|
2022-02-05 23:31:35 +01:00
|
|
|
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
m_guId = guId;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-11-05 23:07:39 +01:00
|
|
|
m_territoryTypeId = territoryTypeId;
|
2018-08-29 21:40:59 +02:00
|
|
|
m_internalName = internalName;
|
|
|
|
m_placeName = placeName;
|
|
|
|
m_lastMobUpdate = 0;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
m_weatherOverride = Common::Weather::None;
|
2022-01-27 21:24:54 +01:00
|
|
|
m_territoryTypeInfo = exdData.getRow< Excel::TerritoryType >( territoryTypeId );
|
2021-11-27 00:53:57 +01:00
|
|
|
m_bgPath = m_territoryTypeInfo->getString( m_territoryTypeInfo->data().LVB );
|
2018-02-01 23:32:59 +01:00
|
|
|
|
2022-01-21 22:55:14 +01:00
|
|
|
m_ident.territoryTypeId = territoryTypeId;
|
2018-08-29 21:40:59 +02:00
|
|
|
loadWeatherRates();
|
2021-11-27 00:53:57 +01:00
|
|
|
|
|
|
|
loadBNpcs();
|
2018-02-14 21:11:23 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_currentWeather = getNextWeather();
|
2018-02-14 21:11:23 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::loadWeatherRates()
|
2018-02-14 21:11:23 +01:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !m_territoryTypeInfo )
|
|
|
|
return;
|
2018-02-14 21:11:23 +01:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& exdData = Common::Service< Data::ExdData >::ref();
|
2018-03-06 00:10:36 +01:00
|
|
|
|
2022-01-27 21:24:54 +01:00
|
|
|
uint8_t weatherRateId = m_territoryTypeInfo->data().WeatherRate > exdData.getIdList< Excel::WeatherRate >().size() ?
|
2022-01-19 00:18:50 +01:00
|
|
|
uint8_t{ 0 } : m_territoryTypeInfo->data().WeatherRate;
|
2018-02-01 23:32:59 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint8_t sumPc = 0;
|
2022-01-27 21:24:54 +01:00
|
|
|
auto weatherRate = exdData.getRow< Excel::WeatherRate >( weatherRateId );
|
2022-01-19 00:18:50 +01:00
|
|
|
for( size_t i = 0; i < 8; ++i )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2022-01-19 00:18:50 +01:00
|
|
|
int32_t weatherId = weatherRate->data().WeatherId[ i ];
|
2018-02-01 23:32:59 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( weatherId == 0 )
|
|
|
|
break;
|
2018-02-01 23:32:59 +01:00
|
|
|
|
2022-01-19 00:18:50 +01:00
|
|
|
sumPc += weatherRate->data().Rate[ i ];
|
2018-08-29 21:40:59 +02:00
|
|
|
m_weatherRateMap[ sumPc ] = weatherId;
|
2022-01-19 00:18:50 +01:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Territory::~Territory() = default;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
bool Territory::init()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
if( scriptMgr.onZoneInit( *this ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
// all good
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
auto& naviMgr = Common::Service< NaviMgr >::ref();
|
2021-11-27 00:53:57 +01:00
|
|
|
std::string lvb = m_territoryTypeInfo->getString( m_territoryTypeInfo->data().LVB );
|
2019-04-19 00:39:42 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
naviMgr.setupTerritory( lvb, m_guId );
|
|
|
|
|
|
|
|
m_pNaviProvider = naviMgr.getNaviProvider( lvb, m_guId );
|
2019-04-19 00:39:42 +02:00
|
|
|
|
2019-04-29 19:59:19 +10:00
|
|
|
if( !m_pNaviProvider )
|
|
|
|
{
|
2019-04-30 21:41:10 +10:00
|
|
|
Logger::warn( "No navmesh found for TerritoryType#{}", getTerritoryTypeId() );
|
2019-04-29 19:59:19 +10:00
|
|
|
}
|
|
|
|
|
2022-01-20 21:37:14 +01:00
|
|
|
onUpdate( 0 );
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::setWeatherOverride( Common::Weather weather )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
m_weatherOverride = weather;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Common::Weather Territory::getCurrentWeather() const
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_currentWeather;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
const FestivalPair& Territory::getCurrentFestival() const
|
2018-02-03 02:11:29 +11:00
|
|
|
{
|
2018-09-01 20:55:28 +10:00
|
|
|
return m_currentFestival;
|
2018-02-03 02:11:29 +11:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::setCurrentFestival( uint16_t festivalId, uint16_t additionalFestivalId )
|
2018-02-03 02:11:29 +11:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& server = Common::Service< World::WorldServer >::ref();
|
2018-09-01 20:55:28 +10:00
|
|
|
m_currentFestival = { festivalId, additionalFestivalId };
|
2018-02-03 02:11:29 +11:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
for( const auto& playerEntry : m_playerMap )
|
|
|
|
{
|
|
|
|
auto player = playerEntry.second;
|
2018-03-20 20:30:05 +11:00
|
|
|
|
2019-10-09 18:42:25 +02:00
|
|
|
auto enableFestival = makeActorControlSelf( player->getId(), SetFestival, festivalId, additionalFestivalId );
|
2021-11-27 00:53:57 +01:00
|
|
|
server.queueForPlayer( playerEntry.second->getCharacterId(), enableFestival );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2018-03-20 20:30:05 +11:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Common::Weather Territory::getNextWeather()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2022-02-05 23:31:35 +01:00
|
|
|
uint32_t unixTime = Common::Util::getTimeSeconds();
|
2018-08-29 21:40:59 +02:00
|
|
|
// Get Eorzea hour for weather start
|
|
|
|
uint32_t bell = unixTime / 175;
|
|
|
|
// Do the magic 'cause for calculations 16:00 is 0, 00:00 is 8 and 08:00 is 16
|
2021-11-27 00:53:57 +01:00
|
|
|
uint32_t increment = ( ( bell + 8 - ( bell % 8 ) ) ) % 24;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Take Eorzea days since unix epoch
|
|
|
|
uint32_t totalDays = ( unixTime / 4200 );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t calcBase = ( totalDays * 0x64 ) + increment;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t step1 = ( calcBase << 0xB ) ^calcBase;
|
|
|
|
uint32_t step2 = ( step1 >> 8 ) ^step1;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto rate = static_cast< uint8_t >( step2 % 0x64 );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
for( auto entry : m_weatherRateMap )
|
|
|
|
{
|
|
|
|
uint8_t sRate = entry.first;
|
2022-02-05 23:31:35 +01:00
|
|
|
auto weatherId = static_cast< Common::Weather >( entry.second );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( rate <= sRate )
|
|
|
|
return weatherId;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
return Common::Weather::FairSkies;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::pushActor( const Entity::GameObjectPtr& pActor )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
float mx = pActor->getPos().x;
|
|
|
|
float my = pActor->getPos().z;
|
|
|
|
uint32_t cx = getPosX( mx );
|
|
|
|
uint32_t cy = getPosY( my );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
CellPtr pCell = getCellPtr( cx, cy );
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !pCell )
|
|
|
|
{
|
|
|
|
pCell = create( cx, cy );
|
2022-02-22 23:47:11 +01:00
|
|
|
pCell->init( cx, cy );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pCell->addActor( pActor );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
pActor->setCellId( { cx, cy } );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
uint32_t cellX = getPosX( pActor->getPos().x );
|
|
|
|
uint32_t cellY = getPosY( pActor->getPos().z );
|
|
|
|
|
|
|
|
uint32_t endX = cellX <= _sizeX ? cellX + 1 : ( _sizeX - 1 );
|
|
|
|
uint32_t endY = cellY <= _sizeY ? cellY + 1 : ( _sizeY - 1 );
|
|
|
|
uint32_t startX = cellX > 0 ? cellX - 1 : 0;
|
|
|
|
uint32_t startY = cellY > 0 ? cellY - 1 : 0;
|
|
|
|
uint32_t posX, posY;
|
|
|
|
|
|
|
|
for( posX = startX; posX <= endX; ++posX )
|
|
|
|
{
|
|
|
|
for( posY = startY; posY <= endY; ++posY )
|
|
|
|
{
|
|
|
|
pCell = getCellPtr( posX, posY );
|
|
|
|
if( pCell )
|
|
|
|
updateInRangeSet( pActor, pCell );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-19 00:39:42 +02:00
|
|
|
int32_t agentId = -1;
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pActor->isPlayer() )
|
|
|
|
{
|
|
|
|
auto pPlayer = pActor->getAsPlayer();
|
|
|
|
|
2019-04-19 00:39:42 +02:00
|
|
|
if( m_pNaviProvider )
|
|
|
|
agentId = m_pNaviProvider->addAgent( *pPlayer );
|
|
|
|
pPlayer->setAgentId( agentId );
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_playerMap[ pPlayer->getId() ] = pPlayer;
|
2022-01-20 21:37:14 +01:00
|
|
|
updateCellActivity( cx, cy, 1 );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2018-09-09 23:56:22 +02:00
|
|
|
else if( pActor->isBattleNpc() )
|
|
|
|
{
|
|
|
|
auto pBNpc = pActor->getAsBNpc();
|
|
|
|
|
2019-04-19 00:39:42 +02:00
|
|
|
if( m_pNaviProvider )
|
|
|
|
agentId = m_pNaviProvider->addAgent( *pBNpc );
|
|
|
|
pBNpc->setAgentId( agentId );
|
|
|
|
|
2018-09-09 23:56:22 +02:00
|
|
|
m_bNpcMap[ pBNpc->getId() ] = pBNpc;
|
2022-01-20 21:37:14 +01:00
|
|
|
updateCellActivity( cx, cy, 1 );
|
2018-09-09 23:56:22 +02:00
|
|
|
|
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
else if( pActor->isEventObj() )
|
|
|
|
{
|
|
|
|
auto pEObj = pActor->getAsEventObj();
|
|
|
|
|
|
|
|
m_eventObjects[ pEObj->getId() ] = pEObj;
|
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::removeActor( const Entity::GameObjectPtr& pActor )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto cellId = pActor->getCellId();
|
|
|
|
CellPtr pCell = getCellPtr( cellId.x, cellId.y );
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pCell && pCell->hasActor( pActor ) )
|
2019-04-07 13:27:56 +02:00
|
|
|
pCell->removeActorFromCell( pActor );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pActor->isPlayer() )
|
|
|
|
{
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-04-19 00:39:42 +02:00
|
|
|
if( m_pNaviProvider )
|
|
|
|
m_pNaviProvider->removeAgent( *pActor->getAsChara() );
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// If it's a player and he's inside boundaries - update his nearby cells
|
|
|
|
if( pActor->getPos().x <= _maxX && pActor->getPos().x >= _minX &&
|
|
|
|
pActor->getPos().z <= _maxY && pActor->getPos().z >= _minY )
|
|
|
|
{
|
|
|
|
uint32_t x = getPosX( pActor->getPos().x );
|
|
|
|
uint32_t y = getPosY( pActor->getPos().z );
|
|
|
|
updateCellActivity( x, y, 3 );
|
|
|
|
}
|
|
|
|
m_playerMap.erase( pActor->getId() );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
onLeaveTerritory( *pActor->getAsPlayer() );
|
2018-02-04 23:35:16 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2018-09-09 23:56:22 +02:00
|
|
|
else if( pActor->isBattleNpc() )
|
|
|
|
{
|
2019-04-19 00:39:42 +02:00
|
|
|
if( m_pNaviProvider )
|
|
|
|
m_pNaviProvider->removeAgent( *pActor->getAsChara() );
|
2018-09-09 23:56:22 +02:00
|
|
|
m_bNpcMap.erase( pActor->getId() );
|
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
else if( pActor->isEventObj() )
|
|
|
|
{
|
|
|
|
m_eventObjects.erase( pActor->getId() );
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// remove from lists of other actors
|
|
|
|
pActor->removeFromInRange();
|
|
|
|
pActor->clearInRangeSet();
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::queuePacketForRange( Entity::Player& sourcePlayer, float range, Network::Packets::FFXIVPacketBasePtr pPacketEntry )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
|
|
|
|
if( teriMgr.isPrivateTerritory( getTerritoryTypeId() ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& server = Common::Service< World::WorldServer >::ref();
|
2020-02-29 22:30:10 +11:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
for( const auto& entry : m_playerMap )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
auto player = entry.second;
|
2022-02-05 23:31:35 +01:00
|
|
|
float distance = Common::Util::distance( sourcePlayer.getPos(), player->getPos() );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
if( ( distance < range ) && sourcePlayer.getId() != player->getId() )
|
|
|
|
{
|
2022-01-27 21:08:43 +01:00
|
|
|
server.queueForPlayer( player->getCharacterId(), pPacketEntry );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::queuePacketForZone( Entity::Player& sourcePlayer, Network::Packets::FFXIVPacketBasePtr pPacketEntry, bool forSelf )
|
2018-11-15 22:30:59 +01:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
|
|
|
|
if( teriMgr.isPrivateTerritory( getTerritoryTypeId() ) )
|
2018-11-15 22:30:59 +01:00
|
|
|
return;
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& server = Common::Service< World::WorldServer >::ref();
|
2020-02-29 22:30:10 +11:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
for( const auto& entry : m_playerMap )
|
2018-11-15 22:30:59 +01:00
|
|
|
{
|
|
|
|
auto player = entry.second;
|
2021-11-27 00:53:57 +01:00
|
|
|
if( ( sourcePlayer.getId() != player->getId() ) || ( ( sourcePlayer.getId() == player->getId() ) && forSelf ) )
|
2018-11-15 22:30:59 +01:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
server.queueForPlayer( player->getCharacterId(), pPacketEntry );
|
2018-11-15 22:30:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
uint32_t Territory::getTerritoryTypeId() const
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-11-05 23:07:39 +01:00
|
|
|
return m_territoryTypeId;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
uint32_t Territory::getGuId() const
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_guId;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
const std::string& Territory::getName() const
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_placeName;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
const std::string& Territory::getInternalName() const
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_internalName;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
const std::string& Territory::getBgPath() const
|
2019-01-25 08:45:00 +01:00
|
|
|
{
|
|
|
|
return m_bgPath;
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
std::size_t Territory::getPopCount() const
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_playerMap.size();
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
bool Territory::checkWeather()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2022-02-05 23:31:35 +01:00
|
|
|
if( m_weatherOverride != Common::Weather::None )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
if( m_weatherOverride != m_currentWeather )
|
|
|
|
{
|
|
|
|
m_currentWeather = m_weatherOverride;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto nextWeather = getNextWeather();
|
|
|
|
if( nextWeather != m_currentWeather )
|
|
|
|
{
|
|
|
|
m_currentWeather = nextWeather;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::updateBNpcs( uint64_t tickCount )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-01-28 15:47:46 +11:00
|
|
|
if( ( tickCount - m_lastMobUpdate ) <= 250 )
|
2019-01-23 22:37:55 +01:00
|
|
|
return;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-01-23 22:37:55 +01:00
|
|
|
m_lastMobUpdate = tickCount;
|
2019-06-02 00:34:22 +10:00
|
|
|
uint64_t currTime = Common::Util::getTimeSeconds();
|
2018-01-29 18:10:11 +11:00
|
|
|
|
2019-01-30 22:37:58 +01:00
|
|
|
// Update loop may move actors from cell to cell, breaking iterator validity
|
2021-11-27 00:53:57 +01:00
|
|
|
std::vector< Entity::BNpcPtr > activeBNpc;
|
2019-01-30 22:37:58 +01:00
|
|
|
|
2019-01-27 01:12:31 +01:00
|
|
|
for( uint32_t y = 0; y < _sizeY; ++y )
|
2019-01-26 13:40:22 +11:00
|
|
|
{
|
2019-01-27 01:12:31 +01:00
|
|
|
for( uint32_t x = 0; x < _sizeX; ++x )
|
2019-01-26 13:40:22 +11:00
|
|
|
{
|
|
|
|
auto cell = getCellPtr( x, y );
|
|
|
|
if( !cell )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// todo: this is a pretty shit because we will visit the same cells multiple times over
|
|
|
|
// ideally we run a pass every tick and cache active cells during that initial pass over every cell
|
|
|
|
// that way we don't have an expensive lookup for every actor
|
|
|
|
|
|
|
|
if( !isCellActive( x, y ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for( const auto& actor : cell->m_actors )
|
|
|
|
{
|
|
|
|
if( actor->isBattleNpc() )
|
2021-11-27 00:53:57 +01:00
|
|
|
activeBNpc.push_back( actor->getAsBNpc() );
|
2019-01-26 13:40:22 +11:00
|
|
|
}
|
|
|
|
}
|
2019-01-23 22:37:55 +01:00
|
|
|
}
|
2019-01-30 22:37:58 +01:00
|
|
|
|
|
|
|
// iterate the cached active bnpcs
|
2021-11-27 00:53:57 +01:00
|
|
|
for( const auto& actor : activeBNpc )
|
2019-01-30 22:37:58 +01:00
|
|
|
actor->update( tickCount );
|
|
|
|
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2019-01-17 23:54:47 +01:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
uint64_t Territory::getLastActivityTime() const
|
2019-04-07 16:01:53 +02:00
|
|
|
{
|
|
|
|
return m_lastActivityTime;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
bool Territory::update( uint64_t tickCount )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
//TODO: this should be moved to a updateWeather call and pulled out of updateSessions
|
|
|
|
bool changedWeather = checkWeather();
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto dt = static_cast< float >( std::difftime( tickCount, m_lastUpdate ) / 1000.f );
|
2019-04-20 15:13:46 +10:00
|
|
|
|
2019-04-19 00:39:42 +02:00
|
|
|
if( m_pNaviProvider )
|
2019-04-20 15:13:46 +10:00
|
|
|
m_pNaviProvider->updateCrowd( dt );
|
2019-04-19 00:39:42 +02:00
|
|
|
|
2019-04-04 23:29:52 +02:00
|
|
|
updateSessions( tickCount, changedWeather );
|
|
|
|
onUpdate( tickCount );
|
2018-02-14 20:44:35 +01:00
|
|
|
|
2019-07-27 13:59:35 +10:00
|
|
|
processEffectResults( tickCount );
|
|
|
|
|
2019-04-20 15:13:46 +10:00
|
|
|
if( !m_playerMap.empty() )
|
2019-04-07 16:01:53 +02:00
|
|
|
m_lastActivityTime = tickCount;
|
|
|
|
|
2019-04-20 15:13:46 +10:00
|
|
|
m_lastUpdate = tickCount;
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2018-02-14 20:44:35 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::updateSessions( uint64_t tickCount, bool changedWeather )
|
2018-02-14 20:44:35 +01:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& server = Common::Service< World::WorldServer >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
// update sessions in this zone
|
2019-04-07 13:27:56 +02:00
|
|
|
for( auto it = m_playerMap.begin(); it != m_playerMap.end(); ++it )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-04-07 13:27:56 +02:00
|
|
|
auto pPlayer = it->second;
|
2018-01-29 18:10:11 +11:00
|
|
|
|
2019-04-07 13:27:56 +02:00
|
|
|
if( !pPlayer )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-04-07 13:27:56 +02:00
|
|
|
m_playerMap.erase( it );
|
|
|
|
return;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// this session is not linked to this area anymore, remove it from zone session list
|
2022-01-10 23:50:44 +01:00
|
|
|
if( pPlayer->getTerritoryId() != m_guId )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2021-11-30 16:29:57 +01:00
|
|
|
Logger::debug( "[{}] removeActor( pPlayer );", pPlayer->getId() );
|
2019-04-07 13:27:56 +02:00
|
|
|
removeActor( pPlayer );
|
|
|
|
return;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( changedWeather )
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto weatherChangePacket = makeZonePacket< FFXIVIpcWeatherId >( pPlayer->getId() );
|
|
|
|
weatherChangePacket->data().WeatherId = static_cast< uint8_t >( m_currentWeather );
|
|
|
|
weatherChangePacket->data().TransitionTime = 5.0f;
|
|
|
|
server.queueForPlayer( pPlayer->getCharacterId(), weatherChangePacket );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// perform session duties
|
2021-11-27 00:53:57 +01:00
|
|
|
auto playerSession = server.getSession( pPlayer->getCharacterId() );
|
|
|
|
if( playerSession )
|
|
|
|
{
|
|
|
|
playerSession->update();
|
|
|
|
}
|
2019-04-07 13:27:56 +02:00
|
|
|
|
|
|
|
// this session is not linked to this area anymore, remove it from zone session list
|
2022-01-10 23:50:44 +01:00
|
|
|
if( pPlayer->getTerritoryId() != getGuId() )
|
2019-04-07 13:27:56 +02:00
|
|
|
return;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
bool Territory::isCellActive( uint32_t x, uint32_t y )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t endX = ( ( x + 1 ) <= _sizeX ) ? x + 1 : ( _sizeX - 1 );
|
|
|
|
uint32_t endY = ( ( y + 1 ) <= _sizeY ) ? y + 1 : ( _sizeY - 1 );
|
|
|
|
uint32_t startX = x > 0 ? x - 1 : 0;
|
|
|
|
uint32_t startY = y > 0 ? y - 1 : 0;
|
|
|
|
uint32_t posX;
|
|
|
|
uint32_t posY;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
CellPtr pCell;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
for( posX = startX; posX <= endX; posX++ )
|
|
|
|
{
|
|
|
|
for( posY = startY; posY <= endY; posY++ )
|
|
|
|
{
|
|
|
|
pCell = getCellPtr( posX, posY );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pCell && ( pCell->hasPlayers() || pCell->isForcedActive() ) )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return false;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::updateCellActivity( uint32_t x, uint32_t y, int32_t radius )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t endX = ( x + radius ) <= _sizeX ? x + radius : ( _sizeX - 1 );
|
|
|
|
uint32_t endY = ( y + radius ) <= _sizeY ? y + radius : ( _sizeY - 1 );
|
|
|
|
uint32_t startX = x - radius > 0 ? x - radius : 0;
|
|
|
|
uint32_t startY = y - radius > 0 ? y - radius : 0;
|
|
|
|
uint32_t posX, posY;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
CellPtr pCell;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
for( posX = startX; posX <= endX; posX++ )
|
|
|
|
{
|
|
|
|
for( posY = startY; posY <= endY; posY++ )
|
|
|
|
{
|
|
|
|
pCell = getCellPtr( posX, posY );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !pCell )
|
|
|
|
{
|
|
|
|
if( isCellActive( posX, posY ) )
|
|
|
|
{
|
|
|
|
pCell = create( posX, posY );
|
2022-02-22 23:47:11 +01:00
|
|
|
pCell->init( posX, posY );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
pCell->setActivity( true );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
//Cell is now active
|
|
|
|
if( isCellActive( posX, posY ) && !pCell->isActive() )
|
|
|
|
{
|
|
|
|
pCell->setActivity( true );
|
|
|
|
}
|
|
|
|
else if( !isCellActive( posX, posY ) && pCell->isActive() )
|
|
|
|
pCell->setActivity( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::updateActorPosition( Entity::GameObject& actor )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
|
|
|
|
2022-01-10 23:50:44 +01:00
|
|
|
if( actor.getTerritoryTypeId() != getTerritoryTypeId() )
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
//actor.checkInRangeActors();
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t cellX = getPosX( actor.getPos().x );
|
|
|
|
uint32_t cellY = getPosY( actor.getPos().z );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( cellX >= _sizeX || cellY >= _sizeY )
|
|
|
|
return;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto pCell = getCellPtr( cellX, cellY );
|
2021-11-27 00:53:57 +01:00
|
|
|
auto oldCellId = actor.getCellId();
|
|
|
|
auto pOldCell = getCellPtr( oldCellId.x, oldCellId.y );
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !pCell )
|
|
|
|
{
|
|
|
|
pCell = create( cellX, cellY );
|
2022-02-22 23:47:11 +01:00
|
|
|
pCell->init( cellX, cellY );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// If object moved cell
|
|
|
|
if( pCell != pOldCell )
|
|
|
|
{
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pOldCell )
|
|
|
|
{
|
2019-04-07 13:27:56 +02:00
|
|
|
pOldCell->removeActorFromCell( actor.shared_from_this() );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
pCell->addActor( actor.shared_from_this() );
|
2021-11-27 00:53:57 +01:00
|
|
|
actor.setCellId( { cellX, cellY } );
|
2018-08-29 21:40:59 +02:00
|
|
|
pOldCell = pCell;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// if player we need to update cell activity
|
|
|
|
// radius = 2 is used in order to update both
|
|
|
|
// old and new cells
|
|
|
|
if( actor.isPlayer() )
|
|
|
|
{
|
|
|
|
updateCellActivity( cellX, cellY, 2 );
|
2021-11-27 00:53:57 +01:00
|
|
|
if( pOldCell )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
// only do the second check if theres -/+ 2 difference
|
|
|
|
if( abs( ( int32_t ) cellX - ( int32_t ) pOldCell->m_posX ) > 2 ||
|
|
|
|
abs( ( int32_t ) cellY - ( int32_t ) pOldCell->m_posY ) > 2 )
|
|
|
|
updateCellActivity( pOldCell->m_posX, pOldCell->m_posY, 2 );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// update in range actor set
|
|
|
|
uint32_t endX = cellX <= _sizeX ? cellX + 1 : ( _sizeX - 1 );
|
|
|
|
uint32_t endY = cellY <= _sizeY ? cellY + 1 : ( _sizeY - 1 );
|
|
|
|
uint32_t startX = cellX > 0 ? cellX - 1 : 0;
|
|
|
|
uint32_t startY = cellY > 0 ? cellY - 1 : 0;
|
|
|
|
uint32_t posX, posY;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
for( posX = startX; posX <= endX; ++posX )
|
|
|
|
{
|
|
|
|
for( posY = startY; posY <= endY; ++posY )
|
|
|
|
{
|
|
|
|
pCell = getCellPtr( posX, posY );
|
|
|
|
if( pCell )
|
|
|
|
updateInRangeSet( actor.shared_from_this(), pCell );
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::updateInRangeSet( Entity::GameObjectPtr pActor, CellPtr pCell )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pCell == nullptr )
|
|
|
|
return;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
// TODO: make sure gms can overwrite this. Potentially temporary solution
|
2020-03-01 01:00:57 +11:00
|
|
|
if( teriMgr.isPrivateTerritory( getTerritoryTypeId() ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
2018-02-08 15:25:59 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto iter = pCell->m_actors.begin();
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
float fRange = teriMgr.getInRangeDistance();
|
2018-08-29 21:40:59 +02:00
|
|
|
int32_t count = 0;
|
|
|
|
while( iter != pCell->m_actors.end() )
|
|
|
|
{
|
|
|
|
auto pCurAct = *iter;
|
|
|
|
++iter;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !pCurAct || pCurAct == pActor )
|
|
|
|
continue;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
float distance = Common::Util::distance( pCurAct->getPos(), pActor->getPos() );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2022-01-10 23:50:44 +01:00
|
|
|
bool isInRange = ( fRange == 0.0f || distance <= fRange );
|
2021-11-27 00:53:57 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
bool isInRangeSet = pActor->isInRangeSet( pCurAct );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Add if range == 0 or distance is withing range.
|
|
|
|
if( isInRange && !isInRangeSet )
|
|
|
|
{
|
2018-02-21 18:06:52 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pActor->isPlayer() && !pActor->getAsPlayer()->isLoadingComplete() )
|
|
|
|
continue;
|
2018-02-21 18:06:52 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pCurAct->isPlayer() && !pCurAct->getAsPlayer()->isLoadingComplete() )
|
|
|
|
continue;
|
2018-02-21 18:06:52 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
pActor->addInRangeActor( pCurAct );
|
|
|
|
pCurAct->addInRangeActor( pActor );
|
2018-02-21 18:06:52 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
else if( !isInRange && isInRangeSet )
|
|
|
|
{
|
|
|
|
pCurAct->removeInRangeActor( *pActor );
|
|
|
|
pActor->removeInRangeActor( *pCurAct );
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::onPlayerZoneIn( Entity::Player& player )
|
2018-02-04 23:35:16 +01:00
|
|
|
{
|
2021-11-30 16:29:57 +01:00
|
|
|
Logger::debug( "[{2}] Territory::onEnterTerritory: Territory#{0}|{1}", getGuId(), getTerritoryTypeId(), player.getId() );
|
2018-02-04 23:35:16 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::onLeaveTerritory( Entity::Player& player )
|
2018-02-04 23:35:16 +01:00
|
|
|
{
|
2021-11-30 16:29:57 +01:00
|
|
|
Logger::debug( "[{2}] Territory::onLeaveTerritory: Territory#{0}|{1}", getGuId(), getTerritoryTypeId(), player.getId() );
|
2018-02-04 23:35:16 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::onUpdate( uint64_t tickCount )
|
2018-02-04 23:35:16 +01:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
updateSpawnPoints();
|
2019-04-17 00:10:32 +02:00
|
|
|
updateBNpcs( tickCount );
|
2018-02-04 23:35:16 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::onFinishLoading( Entity::Player& player )
|
2018-02-06 00:01:23 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::onInitDirector( Entity::Player& player )
|
2018-02-06 00:01:23 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::onEnterTerritory( Sapphire::Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 )
|
2018-03-05 22:10:14 +11:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-16 11:56:59 +01:00
|
|
|
void Territory::addEObj( Entity::EventObjectPtr object )
|
2018-02-10 21:53:16 +11:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !object )
|
|
|
|
return;
|
2018-12-23 03:53:08 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
pushActor( object );
|
2018-02-10 21:53:16 +11:00
|
|
|
|
2022-02-16 11:56:59 +01:00
|
|
|
onAddEObj( object );
|
2018-02-23 23:47:21 +01:00
|
|
|
|
2019-01-23 21:14:17 +01:00
|
|
|
//Logger::debug( "Registered instance eobj: " + std::to_string( object->getId() ) );
|
2018-02-10 21:53:16 +11:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Entity::EventObjectPtr Territory::getEObj( uint32_t objId )
|
2018-02-10 21:53:16 +11:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
auto obj = m_eventObjects.find( objId );
|
|
|
|
if( obj == m_eventObjects.end() )
|
|
|
|
return nullptr;
|
2018-02-10 21:53:16 +11:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return obj->second;
|
2018-02-10 21:53:16 +11:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
InstanceContentPtr Territory::getAsInstanceContent()
|
2018-02-23 23:47:21 +01:00
|
|
|
{
|
2019-07-21 22:33:33 +10:00
|
|
|
return std::dynamic_pointer_cast< InstanceContent, Territory >( shared_from_this() );
|
2018-02-23 23:47:21 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
QuestBattlePtr Territory::getAsQuestBattle()
|
2019-03-31 11:27:11 +02:00
|
|
|
{
|
2019-07-21 22:33:33 +10:00
|
|
|
return std::dynamic_pointer_cast< QuestBattle, Territory >( shared_from_this() );
|
2019-03-31 11:27:11 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
uint32_t Territory::getNextEObjId()
|
2018-02-23 23:47:21 +01:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return ++m_nextEObjId;
|
2018-02-23 23:47:21 +01:00
|
|
|
}
|
2018-02-25 01:23:40 +01:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
uint32_t Territory::getNextActorId()
|
2019-01-13 00:51:31 +01:00
|
|
|
{
|
|
|
|
return ++m_nextActorId;
|
|
|
|
}
|
|
|
|
|
2022-02-16 11:56:59 +01:00
|
|
|
Entity::EventObjectPtr Territory::addEObj( const std::string& name, uint32_t objectId, uint32_t mapLink, uint32_t instanceId,
|
|
|
|
uint8_t state, Common::FFXIVARR_POSITION3 pos, float scale,
|
|
|
|
float rotation, uint8_t permissionInv )
|
2018-02-25 01:23:40 +01:00
|
|
|
{
|
2022-02-16 11:56:59 +01:00
|
|
|
auto eObj = Entity::make_EventObject( getNextEObjId(), objectId, mapLink, instanceId, state, pos, rotation, name, permissionInv );
|
2018-08-29 21:40:59 +02:00
|
|
|
eObj->setScale( scale );
|
2021-11-27 00:53:57 +01:00
|
|
|
|
2022-02-16 11:56:59 +01:00
|
|
|
addEObj( eObj );
|
2018-02-27 02:13:01 +11:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return eObj;
|
2018-02-25 01:23:40 +01:00
|
|
|
}
|
2018-12-02 21:08:38 +11:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
std::shared_ptr< Excel::ExcelStruct< Excel::TerritoryType > > Territory::getTerritoryTypeInfo() const
|
2018-12-02 21:08:38 +11:00
|
|
|
{
|
|
|
|
return m_territoryTypeInfo;
|
2018-12-31 13:54:31 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::updateSpawnPoints()
|
2019-01-08 17:08:48 +01:00
|
|
|
{
|
2022-01-20 21:37:14 +01:00
|
|
|
auto& server = Common::Service< World::WorldServer >::ref();
|
2019-01-13 00:51:31 +01:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
for( auto& spawn : m_spawnInfo )
|
2019-01-08 17:08:48 +01:00
|
|
|
{
|
2022-02-05 23:31:35 +01:00
|
|
|
if( !spawn.bnpcPtr && ( Common::Util::getTimeSeconds() - spawn.timeOfDeath ) > spawn.infoPtr->PopInterval )
|
2019-01-08 17:08:48 +01:00
|
|
|
{
|
2021-12-22 00:40:11 +01:00
|
|
|
auto pBNpc = std::make_shared< Entity::BNpc >( getNextActorId(), spawn.infoPtr, shared_from_this() );
|
2021-12-30 13:57:08 +01:00
|
|
|
pBNpc->init();
|
2021-11-27 00:53:57 +01:00
|
|
|
spawn.bnpcPtr = pBNpc;
|
2019-01-08 17:08:48 +01:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
pushActor( pBNpc );
|
|
|
|
}
|
|
|
|
else if( spawn.bnpcPtr && !spawn.bnpcPtr->isAlive() )
|
|
|
|
{
|
2022-02-05 23:31:35 +01:00
|
|
|
spawn.timeOfDeath = Common::Util::getTimeSeconds();
|
2021-11-27 00:53:57 +01:00
|
|
|
spawn.bnpcPtr.reset();
|
2019-01-08 17:08:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-20 16:10:48 +01:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
uint32_t Territory::getNextEffectSequence()
|
2019-02-11 11:47:04 +11:00
|
|
|
{
|
|
|
|
return m_effectCounter++;
|
|
|
|
}
|
|
|
|
|
2022-02-22 21:46:36 +01:00
|
|
|
Entity::BNpcPtr Territory::createBNpcFromLayoutId( uint32_t levelId, uint32_t hp, Common::BNpcType bnpcType, uint32_t triggerOwnerId )
|
2019-04-17 09:26:29 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto infoPtr = m_bNpcBaseMap.find( levelId );
|
|
|
|
if( infoPtr == m_bNpcBaseMap.end() )
|
2019-04-17 09:26:29 +02:00
|
|
|
return nullptr;
|
|
|
|
|
2021-12-22 00:40:11 +01:00
|
|
|
auto pBNpc = std::make_shared< Entity::BNpc >( getNextActorId(), infoPtr->second, shared_from_this(), hp, bnpcType );
|
2022-01-18 08:03:49 +01:00
|
|
|
pBNpc->setTriggerOwnerId( triggerOwnerId );
|
2021-11-27 00:53:57 +01:00
|
|
|
pushActor( pBNpc );
|
|
|
|
return pBNpc;
|
2019-04-17 09:26:29 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Entity::BNpcPtr Territory::getActiveBNpcByEntityId( uint32_t entityId )
|
2022-01-27 20:03:51 -03:00
|
|
|
{
|
|
|
|
auto it = m_bNpcMap.find( entityId );
|
|
|
|
if( it == m_bNpcMap.end() )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
|
2022-02-22 21:46:36 +01:00
|
|
|
Entity::BNpcPtr Territory::getActiveBNpcByLayoutId( uint32_t instanceId )
|
2019-04-17 09:26:29 +02:00
|
|
|
{
|
2019-07-27 13:59:35 +10:00
|
|
|
for( const auto& bnpcIt : m_bNpcMap )
|
2019-04-17 09:26:29 +02:00
|
|
|
{
|
2021-12-22 00:40:11 +01:00
|
|
|
if( bnpcIt.second->getLayoutId() == instanceId )
|
2019-04-17 09:26:29 +02:00
|
|
|
return bnpcIt.second;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2019-04-19 00:39:42 +02:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
Entity::BNpcPtr Territory::getActiveBNpcByInstanceIdAndTriggerOwner( uint32_t instanceId, uint32_t triggerOwnerId )
|
2022-01-27 21:08:43 +01:00
|
|
|
{
|
|
|
|
for( const auto& bnpcIt : m_bNpcMap )
|
|
|
|
{
|
|
|
|
if( bnpcIt.second->getLayoutId() == instanceId && bnpcIt.second->getTriggerOwnerId() == triggerOwnerId )
|
|
|
|
return bnpcIt.second;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
std::shared_ptr< World::Navi::NaviProvider > Territory::getNaviProvider()
|
2019-04-19 00:39:42 +02:00
|
|
|
{
|
|
|
|
return m_pNaviProvider;
|
|
|
|
}
|
2019-07-27 13:59:35 +10:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::addEffectResult( World::Action::EffectResultPtr result )
|
2019-07-27 13:59:35 +10:00
|
|
|
{
|
|
|
|
m_effectResults.emplace_back( std::move( result ) );
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::processEffectResults( uint64_t tickCount )
|
2019-07-27 13:59:35 +10:00
|
|
|
|
|
|
|
{
|
|
|
|
// todo: move this to generic territory/instance delay wrapper cause it might be useful scheduling other things
|
|
|
|
for( auto it = m_effectResults.begin(); it != m_effectResults.end(); )
|
|
|
|
{
|
|
|
|
auto effect = *it;
|
|
|
|
|
|
|
|
if( tickCount < effect->getDelay() )
|
|
|
|
{
|
|
|
|
++it;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
effect->execute();
|
|
|
|
|
|
|
|
it = m_effectResults.erase( it );
|
|
|
|
}
|
2021-08-16 17:18:29 +09:00
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
bool Territory::loadBNpcs()
|
2021-08-16 17:18:29 +09:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::ZONE_SEL_BNPCS_BY_TERI );
|
|
|
|
stmt->setUInt( 1, getTerritoryTypeId() );
|
|
|
|
auto res = db.query( stmt );
|
2021-08-16 17:18:29 +09:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
while( res->next() )
|
2021-08-16 17:18:29 +09:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto bnpc = std::make_shared< Common::BNPCInstanceObject >();
|
|
|
|
|
|
|
|
bnpc->territoryType = res->getInt( 1 );
|
|
|
|
bnpc->bnpcName = res->getString( 3 );
|
|
|
|
bnpc->instanceId = res->getInt( 4 );
|
|
|
|
bnpc->x = res->getFloat( 5 );
|
|
|
|
bnpc->y = res->getFloat( 6 );
|
|
|
|
bnpc->z = res->getFloat( 7 );
|
|
|
|
bnpc->BaseId = res->getInt( 8 );
|
|
|
|
bnpc->PopWeather = res->getInt( 9 );
|
|
|
|
bnpc->PopTimeStart = res->getInt( 10 );
|
|
|
|
bnpc->PopTimeEnd = res->getInt( 11 );
|
|
|
|
bnpc->MoveAI = res->getInt( 12 );
|
|
|
|
bnpc->WanderingRange = res->getInt( 13 );
|
|
|
|
bnpc->Route = res->getInt( 14 );
|
|
|
|
bnpc->EventGroup = res->getInt( 15 );
|
|
|
|
bnpc->NameId = res->getInt( 16 );
|
|
|
|
bnpc->DropItem = res->getInt( 17 );
|
|
|
|
bnpc->SenseRangeRate = res->getFloat( 18 );
|
|
|
|
bnpc->Level = res->getInt( 19 );
|
|
|
|
bnpc->ActiveType = res->getInt( 20 );
|
|
|
|
bnpc->PopInterval = res->getInt( 21 );
|
|
|
|
bnpc->PopRate = res->getInt( 22 );
|
|
|
|
bnpc->PopEvent = res->getInt( 23 );
|
|
|
|
bnpc->LinkGroup = res->getInt( 24 );
|
|
|
|
bnpc->LinkFamily = res->getInt( 25 );
|
|
|
|
bnpc->LinkRange = res->getInt( 26 );
|
|
|
|
bnpc->LinkCountLimit = res->getInt( 27 );
|
|
|
|
bnpc->NonpopInitZone = res->getInt( 28 );
|
|
|
|
bnpc->InvalidRepop = res->getInt( 29 );
|
|
|
|
bnpc->LinkParent = res->getInt( 30 );
|
|
|
|
bnpc->LinkOverride = res->getInt( 31 );
|
|
|
|
bnpc->LinkReply = res->getInt( 32 );
|
|
|
|
bnpc->HorizontalPopRange = res->getFloat( 33 );
|
|
|
|
bnpc->VerticalPopRange = res->getFloat( 34 );
|
|
|
|
bnpc->BNpcBaseData = res->getInt( 35 );
|
|
|
|
bnpc->RepopId = res->getInt( 36 );
|
|
|
|
bnpc->BNPCRankId = res->getInt( 37 );
|
|
|
|
bnpc->TerritoryRange = res->getInt( 38 );
|
|
|
|
bnpc->BoundInstanceID = res->getInt( 39 );
|
|
|
|
bnpc->FateLayoutLabelId = res->getInt( 40 );
|
|
|
|
bnpc->NormalAI = res->getInt( 41 );
|
|
|
|
bnpc->ServerPathId = res->getInt( 42 );
|
|
|
|
bnpc->EquipmentID = res->getInt( 43 );
|
|
|
|
bnpc->CustomizeID = res->getInt( 44 );
|
|
|
|
bnpc->rotation = res->getFloat( 45 );
|
2021-12-17 14:53:13 +01:00
|
|
|
bnpc->Nonpop = res->getInt( 46 );
|
2021-11-27 00:53:57 +01:00
|
|
|
|
|
|
|
m_bNpcBaseMap[ bnpc->instanceId ] = bnpc;
|
|
|
|
|
2021-12-17 14:53:13 +01:00
|
|
|
if( bnpc->Nonpop != 1 )
|
|
|
|
{
|
|
|
|
SpawnInfo info;
|
|
|
|
info.bnpcPtr = nullptr;
|
|
|
|
info.infoPtr = bnpc;
|
|
|
|
info.lastSpawn = 0;
|
|
|
|
info.timeOfDeath = 0;
|
|
|
|
|
|
|
|
m_spawnInfo.emplace_back( info );
|
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
|
2021-08-16 17:18:29 +09:00
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
void Territory::onEventHandlerOrder( Entity::Player& player, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4 )
|
2021-11-27 00:53:57 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2022-01-21 22:55:14 +01:00
|
|
|
|
2022-02-05 23:31:35 +01:00
|
|
|
const Common::TerritoryIdent& Territory::getTerritoryIdent() const
|
2022-01-21 22:55:14 +01:00
|
|
|
{
|
|
|
|
return m_ident;
|
|
|
|
}
|