2022-07-16 23:19:40 +00:00
# include "Transport.hpp"
2021-03-17 19:07:40 +00:00
# include "servers/CNShardServer.hpp"
2022-07-16 23:19:40 +00:00
2020-08-29 11:43:33 +00:00
# include "PlayerManager.hpp"
2021-03-16 22:29:13 +00:00
# include "Nanos.hpp"
2020-10-06 19:53:21 +00:00
# include "TableData.hpp"
2022-07-16 23:19:40 +00:00
# include "Entities.hpp"
# include "NPCManager.hpp"
2021-03-13 22:55:16 +00:00
# include "MobAI.hpp"
2020-08-29 11:43:33 +00:00
2020-09-17 02:27:21 +00:00
# include <unordered_map>
2020-09-23 14:53:06 +00:00
# include <cmath>
2020-09-13 20:26:16 +00:00
2021-03-16 22:29:13 +00:00
using namespace Transport ;
2021-03-16 21:06:10 +00:00
2021-03-16 22:29:13 +00:00
std : : map < int32_t , TransportRoute > Transport : : Routes ;
std : : map < int32_t , TransportLocation > Transport : : Locations ;
2021-05-03 19:29:33 +00:00
std : : vector < NPCPath > Transport : : NPCPaths ;
2021-05-01 15:04:28 +00:00
std : : map < int32_t , std : : queue < Vec3 > > Transport : : SkywayPaths ;
std : : unordered_map < CNSocket * , std : : queue < Vec3 > > Transport : : SkywayQueues ;
std : : unordered_map < int32_t , std : : queue < Vec3 > > Transport : : NPCQueues ;
2020-09-13 20:26:16 +00:00
2021-03-16 21:06:10 +00:00
static void transportRegisterLocationHandler ( CNSocket * sock , CNPacketData * data ) {
2021-03-20 23:50:57 +00:00
auto transport = ( sP_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION * ) data - > buf ;
2020-09-13 20:26:16 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-09-22 01:03:48 +00:00
bool newReg = false ; // this is a new registration
2020-09-17 13:22:06 +00:00
//std::cout << "request to register transport, eTT " << transport->eTT << ", locID " << transport->iLocationID << ", npc " << transport->iNPC_ID << std::endl;
2020-09-13 20:26:16 +00:00
if ( transport - > eTT = = 1 ) { // S.C.A.M.P.E.R.
if ( transport - > iLocationID < 1 | | transport - > iLocationID > 31 ) { // sanity check
std : : cout < < " [WARN] S.C.A.M.P.E.R. location ID " < < transport - > iLocationID < < " is out of bounds " < < std : : endl ;
INITSTRUCT ( sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL , failResp ) ;
failResp . eTT = transport - > eTT ;
failResp . iErrorCode = 0 ; // TODO: review what error code to use here
failResp . iLocationID = transport - > iLocationID ;
2021-03-20 23:50:57 +00:00
sock - > sendPacket ( failResp , P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL ) ;
2020-09-13 20:26:16 +00:00
return ;
}
2020-09-22 01:03:48 +00:00
// update registration bitfield using bitmask
2021-01-05 11:43:11 +00:00
uint32_t newScamperFlag = plr - > iWarpLocationFlag | ( 1UL < < ( transport - > iLocationID - 1 ) ) ;
2020-09-22 01:03:48 +00:00
if ( newScamperFlag ! = plr - > iWarpLocationFlag ) {
plr - > iWarpLocationFlag = newScamperFlag ;
newReg = true ;
}
2020-09-13 20:26:16 +00:00
} else if ( transport - > eTT = = 2 ) { // Monkey Skyway System
if ( transport - > iLocationID < 1 | | transport - > iLocationID > 127 ) { // sanity check
std : : cout < < " [WARN] Skyway location ID " < < transport - > iLocationID < < " is out of bounds " < < std : : endl ;
INITSTRUCT ( sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL , failResp ) ;
failResp . eTT = transport - > eTT ;
failResp . iErrorCode = 0 ; // TODO: review what error code to use here
failResp . iLocationID = transport - > iLocationID ;
2021-03-20 23:50:57 +00:00
sock - > sendPacket ( failResp , P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL ) ;
2020-09-13 20:26:16 +00:00
return ;
}
2020-09-14 13:53:48 +00:00
/*
2020-09-22 01:03:48 +00:00
* assuming the two bitfields are just stuck together to make a longer one , do a similar operation
2020-09-13 20:26:16 +00:00
*/
2021-01-05 11:43:11 +00:00
int index = transport - > iLocationID > 64 ? 1 : 0 ;
uint64_t newMonkeyFlag = plr - > aSkywayLocationFlag [ index ] | ( 1ULL < < ( index ? transport - > iLocationID - 65 : transport - > iLocationID - 1 ) ) ;
if ( newMonkeyFlag ! = plr - > aSkywayLocationFlag [ index ] ) {
plr - > aSkywayLocationFlag [ index ] = newMonkeyFlag ;
2020-09-22 01:03:48 +00:00
newReg = true ;
2020-09-17 02:27:21 +00:00
}
2020-09-13 20:26:16 +00:00
} else {
std : : cout < < " [WARN] Unknown mode of transport; eTT = " < < transport - > eTT < < std : : endl ;
INITSTRUCT ( sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL , failResp ) ;
failResp . eTT = transport - > eTT ;
failResp . iErrorCode = 0 ; // TODO: review what error code to use here
failResp . iLocationID = transport - > iLocationID ;
2021-03-20 23:50:57 +00:00
sock - > sendPacket ( failResp , P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL ) ;
2020-09-13 20:26:16 +00:00
return ;
}
2020-08-29 11:43:33 +00:00
2020-09-22 01:03:48 +00:00
if ( ! newReg )
return ; // don't send new registration message
2020-09-13 20:26:16 +00:00
2020-09-22 01:03:48 +00:00
INITSTRUCT ( sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC , resp ) ;
2020-09-13 20:26:16 +00:00
// response parameters
2020-08-29 11:43:33 +00:00
resp . eTT = transport - > eTT ;
resp . iLocationID = transport - > iLocationID ;
2020-09-13 20:26:16 +00:00
resp . iWarpLocationFlag = plr - > iWarpLocationFlag ;
resp . aWyvernLocationFlag [ 0 ] = plr - > aSkywayLocationFlag [ 0 ] ;
resp . aWyvernLocationFlag [ 1 ] = plr - > aSkywayLocationFlag [ 1 ] ;
2020-08-29 11:43:33 +00:00
2021-03-20 23:50:57 +00:00
sock - > sendPacket ( resp , P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC ) ;
2020-08-29 11:43:33 +00:00
}
2020-09-13 20:26:16 +00:00
2021-03-16 21:06:10 +00:00
static void transportWarpHandler ( CNSocket * sock , CNPacketData * data ) {
2021-03-20 23:50:57 +00:00
auto req = ( sP_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION * ) data - > buf ;
2020-09-13 20:26:16 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
/*
* req :
* eIL - - inventory type
* iNPC_ID - - the ID of the NPC who is warping you
* iTransporationID - - iVehicleID
* iSlotNum - - inventory slot number
*/
2020-09-17 02:27:21 +00:00
if ( Routes . find ( req - > iTransporationID ) = = Routes . end ( ) | | Routes [ req - > iTransporationID ] . cost > plr - > money ) { // sanity check
2020-09-13 20:26:16 +00:00
INITSTRUCT ( sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_FAIL , failResp ) ;
failResp . iErrorCode = 0 ; // TODO: error code
failResp . iTransportationID = req - > iTransporationID ;
2021-03-20 23:50:57 +00:00
sock - > sendPacket ( failResp , P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_FAIL ) ;
2020-09-13 20:26:16 +00:00
return ;
}
TransportRoute route = Routes [ req - > iTransporationID ] ;
plr - > money - = route . cost ;
2020-09-14 13:53:48 +00:00
2020-11-27 03:58:56 +00:00
TransportLocation * target = nullptr ;
2020-09-22 01:03:48 +00:00
switch ( route . type ) {
2020-09-13 20:26:16 +00:00
case 1 : // S.C.A.M.P.E.R.
2020-11-27 03:58:56 +00:00
target = & Locations [ route . end ] ;
2020-09-13 20:26:16 +00:00
break ;
case 2 : // Monkey Skyway
2020-11-26 15:01:48 +00:00
// set last safe coords
plr - > lastX = plr - > x ;
plr - > lastY = plr - > y ;
plr - > lastZ = plr - > z ;
2020-09-22 01:03:48 +00:00
if ( SkywayPaths . find ( route . mssRouteNum ) ! = SkywayPaths . end ( ) ) { // check if route exists
2021-03-16 22:29:13 +00:00
Nanos : : summonNano ( sock , - 1 ) ; // make sure that no nano is active during the ride
2020-09-22 01:03:48 +00:00
SkywayQueues [ sock ] = SkywayPaths [ route . mssRouteNum ] ; // set socket point queue to route
2020-11-26 15:01:48 +00:00
plr - > onMonkey = true ;
2020-09-22 01:03:48 +00:00
break ;
2020-10-06 19:53:21 +00:00
} else if ( TableData : : RunningSkywayRoutes . find ( route . mssRouteNum ) ! = TableData : : RunningSkywayRoutes . end ( ) ) {
2021-05-01 15:04:28 +00:00
std : : vector < Vec3 > * _route = & TableData : : RunningSkywayRoutes [ route . mssRouteNum ] ;
2021-03-16 22:29:13 +00:00
Nanos : : summonNano ( sock , - 1 ) ;
2020-10-06 19:53:21 +00:00
testMssRoute ( sock , _route ) ;
2020-11-26 15:01:48 +00:00
plr - > onMonkey = true ;
2020-10-06 19:53:21 +00:00
break ;
2020-09-22 01:03:48 +00:00
}
// refund and send alert packet
plr - > money + = route . cost ;
INITSTRUCT ( sP_FE2CL_ANNOUNCE_MSG , alert ) ;
alert . iAnnounceType = 0 ; // don't think this lets us make a confirm dialog
alert . iDuringTime = 3 ;
2020-10-04 17:50:58 +00:00
U8toU16 ( " Skyway route " + std : : to_string ( route . mssRouteNum ) + " isn't pathed yet. You will not be charged any taros. " , ( char16_t * ) alert . szAnnounceMsg , sizeof ( alert . szAnnounceMsg ) ) ;
2021-03-20 23:50:57 +00:00
sock - > sendPacket ( alert , P_FE2CL_ANNOUNCE_MSG ) ;
2020-09-22 01:03:48 +00:00
std : : cout < < " [WARN] MSS route " < < route . mssRouteNum < < " not pathed " < < std : : endl ;
2020-09-13 20:26:16 +00:00
break ;
default :
std : : cout < < " [WARN] Unknown tranportation type " < < route . type < < std : : endl ;
break ;
}
INITSTRUCT ( sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC , resp ) ;
// response parameters
resp . eTT = route . type ;
resp . iCandy = plr - > money ;
2020-11-27 03:58:56 +00:00
resp . iX = ( target = = nullptr ) ? plr - > x : target - > x ;
resp . iY = ( target = = nullptr ) ? plr - > y : target - > y ;
resp . iZ = ( target = = nullptr ) ? plr - > z : target - > z ;
2021-03-20 23:50:57 +00:00
sock - > sendPacket ( resp , P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC ) ;
2020-11-27 03:58:56 +00:00
if ( target = = nullptr )
return ;
2022-07-22 00:40:33 +00:00
2020-11-27 03:58:56 +00:00
// we warped; update position and chunks
2022-07-22 00:40:33 +00:00
PlayerManager : : updatePlayerPositionForWarp ( sock , target - > x , target - > y , target - > z , INSTANCE_OVERWORLD ) ;
2020-09-17 02:27:21 +00:00
}
2021-05-01 15:04:28 +00:00
void Transport : : testMssRoute ( CNSocket * sock , std : : vector < Vec3 > * route ) {
2020-10-06 19:53:21 +00:00
int speed = 1500 ; // TODO: make this adjustable
2021-05-01 15:04:28 +00:00
std : : queue < Vec3 > path ;
Vec3 last = route - > front ( ) ; // start pos
2020-10-06 19:53:21 +00:00
for ( int i = 1 ; i < route - > size ( ) ; i + + ) {
2021-05-01 15:04:28 +00:00
Vec3 coords = route - > at ( i ) ;
2021-03-16 22:29:13 +00:00
Transport : : lerp ( & path , last , coords , speed ) ;
2020-10-06 19:53:21 +00:00
path . push ( coords ) ; // add keyframe to the queue
last = coords ; // update start pos
}
SkywayQueues [ sock ] = path ;
}
2020-09-22 01:03:48 +00:00
/*
* Go through every socket that has broomstick points queued up , and advance to the next point .
* If the player has disconnected or finished the route , clean up and remove them from the queue .
*/
2021-03-16 21:06:10 +00:00
static void stepSkywaySystem ( ) {
2020-10-05 00:03:13 +00:00
2020-09-22 01:03:48 +00:00
// using an unordered map so we can remove finished players in one iteration
2021-05-01 15:04:28 +00:00
std : : unordered_map < CNSocket * , std : : queue < Vec3 > > : : iterator it = SkywayQueues . begin ( ) ;
2020-09-22 01:03:48 +00:00
while ( it ! = SkywayQueues . end ( ) ) {
2020-09-17 02:27:21 +00:00
2021-05-01 15:04:28 +00:00
std : : queue < Vec3 > * queue = & it - > second ;
2020-10-05 00:03:13 +00:00
2020-12-03 20:33:14 +00:00
if ( PlayerManager : : players . find ( it - > first ) = = PlayerManager : : players . end ( ) ) {
2020-09-22 01:03:48 +00:00
// pluck out dead socket + update iterator
it = SkywayQueues . erase ( it ) ;
2020-09-17 13:22:06 +00:00
continue ;
2020-09-17 02:27:21 +00:00
}
2020-09-17 13:22:06 +00:00
2020-12-03 20:33:14 +00:00
Player * plr = PlayerManager : : getPlayer ( it - > first ) ;
2020-09-17 13:22:06 +00:00
if ( queue - > empty ( ) ) {
2020-09-17 02:27:21 +00:00
// send dismount packet
INITSTRUCT ( sP_FE2CL_REP_PC_RIDING_SUCC , rideSucc ) ;
2020-09-17 13:22:06 +00:00
INITSTRUCT ( sP_FE2CL_PC_RIDING , rideBroadcast ) ;
2020-09-22 01:03:48 +00:00
rideSucc . iPC_ID = plr - > iID ;
2020-09-17 02:27:21 +00:00
rideSucc . eRT = 0 ;
2020-09-22 01:03:48 +00:00
rideBroadcast . iPC_ID = plr - > iID ;
2020-09-17 13:22:06 +00:00
rideBroadcast . eRT = 0 ;
2021-03-20 23:50:57 +00:00
it - > first - > sendPacket ( rideSucc , P_FE2CL_REP_PC_RIDING_SUCC ) ;
2020-09-22 01:03:48 +00:00
// send packet to players in view
2021-03-20 23:50:57 +00:00
PlayerManager : : sendToViewable ( it - > first , rideBroadcast , P_FE2CL_PC_RIDING ) ;
2020-09-22 01:03:48 +00:00
it = SkywayQueues . erase ( it ) ; // remove player from tracking map + update iterator
2020-11-26 15:01:48 +00:00
plr - > onMonkey = false ;
2020-09-22 01:03:48 +00:00
} else {
2021-05-01 15:04:28 +00:00
Vec3 point = queue - > front ( ) ; // get point
2020-09-17 02:27:21 +00:00
queue - > pop ( ) ; // remove point from front of queue
INITSTRUCT ( sP_FE2CL_PC_BROOMSTICK_MOVE , bmstk ) ;
2020-09-22 01:03:48 +00:00
bmstk . iPC_ID = plr - > iID ;
2020-09-17 02:27:21 +00:00
bmstk . iToX = point . x ;
bmstk . iToY = point . y ;
bmstk . iToZ = point . z ;
2021-03-20 23:50:57 +00:00
it - > first - > sendPacket ( bmstk , P_FE2CL_PC_BROOMSTICK_MOVE ) ;
2020-09-22 01:03:48 +00:00
// set player location to point to update viewables
2020-11-18 00:07:04 +00:00
PlayerManager : : updatePlayerPosition ( it - > first , point . x , point . y , point . z , plr - > instanceID , plr - > angle ) ;
2020-09-17 13:22:06 +00:00
// send packet to players in view
2021-03-20 23:50:57 +00:00
PlayerManager : : sendToViewable ( it - > first , bmstk , P_FE2CL_PC_BROOMSTICK_MOVE ) ;
2020-09-17 02:27:21 +00:00
it + + ; // go to next entry in map
}
}
2020-09-13 20:26:16 +00:00
}
2020-09-23 14:29:29 +00:00
2021-03-16 21:06:10 +00:00
static void stepNPCPathing ( ) {
2020-09-23 14:29:29 +00:00
// all NPC pathing queues
2021-05-01 15:04:28 +00:00
std : : unordered_map < int32_t , std : : queue < Vec3 > > : : iterator it = NPCQueues . begin ( ) ;
2020-09-23 14:29:29 +00:00
while ( it ! = NPCQueues . end ( ) ) {
2021-05-01 15:04:28 +00:00
std : : queue < Vec3 > * queue = & it - > second ;
2020-09-23 14:29:29 +00:00
BaseNPC * npc = nullptr ;
if ( NPCManager : : NPCs . find ( it - > first ) ! = NPCManager : : NPCs . end ( ) )
npc = NPCManager : : NPCs [ it - > first ] ;
2020-10-12 19:03:18 +00:00
if ( npc = = nullptr | | queue - > empty ( ) ) {
2020-09-23 14:29:29 +00:00
// pluck out dead path + update iterator
it = NPCQueues . erase ( it ) ;
continue ;
}
2020-10-13 19:44:43 +00:00
// skip if not simulating mobs
2022-04-13 19:09:43 +00:00
if ( npc - > kind = = EntityKind : : MOB & & ! MobAI : : simulateMobs ) {
2020-10-13 19:44:43 +00:00
it + + ;
continue ;
}
2020-10-12 19:03:18 +00:00
// do not roam if not roaming
2022-04-13 19:09:43 +00:00
if ( npc - > kind = = EntityKind : : MOB & & ( ( Mob * ) npc ) - > state ! = AIState : : ROAMING ) {
2020-10-12 19:03:18 +00:00
it + + ;
continue ;
}
2021-05-01 15:04:28 +00:00
Vec3 point = queue - > front ( ) ; // get point
2020-09-23 14:29:29 +00:00
queue - > pop ( ) ; // remove point from front of queue
// calculate displacement
2021-04-14 00:57:24 +00:00
int dXY = hypot ( point . x - npc - > x , point . y - npc - > y ) ; // XY plane distance
int distanceBetween = hypot ( dXY , point . z - npc - > z ) ; // total distance
2020-09-23 14:29:29 +00:00
// update NPC location to update viewables
2021-06-20 18:37:37 +00:00
NPCManager : : updateNPCPosition ( npc - > id , point . x , point . y , point . z , npc - > instanceID , npc - > angle ) ;
2020-09-23 14:29:29 +00:00
2021-03-21 02:54:24 +00:00
// TODO: move walking logic into Entity stack
2021-06-20 18:12:40 +00:00
switch ( npc - > kind ) {
2022-04-13 19:09:43 +00:00
case EntityKind : : BUS :
2020-09-23 14:29:29 +00:00
INITSTRUCT ( sP_FE2CL_TRANSPORTATION_MOVE , busMove ) ;
2021-03-21 02:54:24 +00:00
2020-09-23 14:29:29 +00:00
busMove . eTT = 3 ;
2021-06-20 18:37:37 +00:00
busMove . iT_ID = npc - > id ;
2020-09-23 14:29:29 +00:00
busMove . iMoveStyle = 0 ; // ???
busMove . iToX = point . x ;
busMove . iToY = point . y ;
busMove . iToZ = point . z ;
busMove . iSpeed = distanceBetween ; // set to distance to match how monkeys work
2020-10-12 19:03:18 +00:00
NPCManager : : sendToViewable ( npc , & busMove , P_FE2CL_TRANSPORTATION_MOVE , sizeof ( sP_FE2CL_TRANSPORTATION_MOVE ) ) ;
2020-09-23 14:29:29 +00:00
break ;
2022-04-13 19:09:43 +00:00
case EntityKind : : MOB :
2021-03-13 22:55:16 +00:00
MobAI : : incNextMovement ( ( Mob * ) npc ) ;
2020-10-12 19:03:18 +00:00
/* fallthrough */
2020-09-23 14:29:29 +00:00
default :
INITSTRUCT ( sP_FE2CL_NPC_MOVE , move ) ;
2021-06-20 18:37:37 +00:00
move . iNPC_ID = npc - > id ;
2020-09-23 14:29:29 +00:00
move . iMoveStyle = 0 ; // ???
move . iToX = point . x ;
move . iToY = point . y ;
move . iToZ = point . z ;
2020-09-24 14:14:37 +00:00
move . iSpeed = distanceBetween ;
2020-09-23 14:29:29 +00:00
2020-10-12 19:03:18 +00:00
NPCManager : : sendToViewable ( npc , & move , P_FE2CL_NPC_MOVE , sizeof ( sP_FE2CL_NPC_MOVE ) ) ;
2020-09-23 14:29:29 +00:00
break ;
}
2020-10-12 19:03:18 +00:00
/*
2021-05-09 12:37:36 +00:00
* If this path should be repeated , move processed point to the back to maintain cycle .
2020-10-12 19:03:18 +00:00
*/
2021-05-09 12:37:36 +00:00
if ( npc - > loopingPath )
2020-10-12 19:03:18 +00:00
queue - > push ( point ) ;
2020-09-23 14:29:29 +00:00
it + + ; // go to next entry in map
}
}
2021-03-16 21:06:10 +00:00
static void tickTransportationSystem ( CNServer * serv , time_t currTime ) {
stepNPCPathing ( ) ;
stepSkywaySystem ( ) ;
}
2020-09-23 14:29:29 +00:00
/*
* Linearly interpolate between two points and insert the results into a queue .
*/
2021-05-01 15:04:28 +00:00
void Transport : : lerp ( std : : queue < Vec3 > * queue , Vec3 start , Vec3 end , int gapSize , float curve ) {
2020-09-23 14:29:29 +00:00
int dXY = hypot ( end . x - start . x , end . y - start . y ) ; // XY plane distance
int distanceBetween = hypot ( dXY , end . z - start . z ) ; // total distance
2020-09-26 22:45:19 +00:00
int lerps = distanceBetween / gapSize ; // number of intermediate points to add
for ( int i = 1 ; i < = lerps ; i + + ) {
2021-05-01 15:04:28 +00:00
Vec3 lerp ;
2020-09-23 14:29:29 +00:00
// lerp math
2020-09-26 22:45:19 +00:00
//float frac = i / (lerps + 1);
float frac = powf ( i , curve ) / powf ( lerps + 1 , curve ) ;
2020-09-23 14:29:29 +00:00
lerp . x = ( start . x * ( 1.0f - frac ) ) + ( end . x * frac ) ;
lerp . y = ( start . y * ( 1.0f - frac ) ) + ( end . y * frac ) ;
lerp . z = ( start . z * ( 1.0f - frac ) ) + ( end . z * frac ) ;
queue - > push ( lerp ) ; // add lerp'd point
}
}
2021-05-01 15:04:28 +00:00
void Transport : : lerp ( std : : queue < Vec3 > * queue , Vec3 start , Vec3 end , int gapSize ) {
2020-09-26 22:45:19 +00:00
lerp ( queue , start , end , gapSize , 1 ) ;
}
2021-03-16 21:06:10 +00:00
2021-05-06 01:17:06 +00:00
/*
* Find and return the first path that targets either the type or the ID .
* If no matches are found , return nullptr
*/
NPCPath * Transport : : findApplicablePath ( int32_t id , int32_t type , int taskID ) {
NPCPath * match = nullptr ;
for ( auto _path = Transport : : NPCPaths . begin ( ) ; _path ! = Transport : : NPCPaths . end ( ) ; _path + + ) {
// task ID for the path must match so escorts don't start early
if ( _path - > escortTaskID ! = taskID )
continue ;
// search target IDs
for ( int32_t pID : _path - > targetIDs ) {
if ( id = = pID ) {
match = & ( * _path ) ;
break ;
}
}
if ( match ! = nullptr )
break ; // early break for ID matches, since ID has higher priority than type
// search target types
for ( int32_t pType : _path - > targetTypes ) {
if ( type = = pType ) {
match = & ( * _path ) ;
break ;
}
}
if ( match ! = nullptr )
break ;
}
return match ;
}
2021-05-06 01:22:11 +00:00
void Transport : : constructPathNPC ( int32_t id , NPCPath * path ) {
BaseNPC * npc = NPCManager : : NPCs [ id ] ;
2024-10-19 02:26:09 +00:00
if ( npc - > kind = = EntityKind : : MOB ) {
auto mob = ( Mob * ) npc ;
mob - > staticPath = true ;
Vec3 firstPoint = path - > points . front ( ) ;
// Ensure that the first point coincides with the mob's spawn point.
if ( mob - > spawnX ! = firstPoint . x | | mob - > spawnY ! = firstPoint . y ) {
std : : cout < < " [FATAL] The first point of the route for mob " < < mob - > id < < " (type " < < mob - > type
< < " ) does not correspond with its spawn point. " < < std : : endl ;
exit ( 1 ) ;
}
}
2021-05-09 12:37:36 +00:00
npc - > loopingPath = path - > isLoop ;
2021-05-06 01:22:11 +00:00
// Interpolate
std : : vector < Vec3 > pathPoints = path - > points ;
std : : queue < Vec3 > points ;
auto _point = pathPoints . begin ( ) ;
Vec3 from = * _point ; // point A coords
for ( _point + + ; _point ! = pathPoints . end ( ) ; _point + + ) { // loop through all point Bs
Vec3 to = * _point ; // point B coords
// add point A to the queue
if ( path - > isRelative ) {
// relative; the NPCs current position is assumed to be its spawn point
Vec3 fromReal = { from . x + npc - > x , from . y + npc - > y , from . z + npc - > z } ;
Vec3 toReal = { to . x + npc - > x , to . y + npc - > y , to . z + npc - > z } ;
points . push ( fromReal ) ;
Transport : : lerp ( & points , fromReal , toReal , path - > speed ) ; // lerp from A to B
}
else {
// absolute
points . push ( from ) ;
Transport : : lerp ( & points , from , to , path - > speed ) ; // lerp from A to B
}
from = to ; // update point A
}
Transport : : NPCQueues [ id ] = points ;
}
2021-03-16 22:29:13 +00:00
void Transport : : init ( ) {
2021-03-16 21:06:10 +00:00
REGISTER_SHARD_TIMER ( tickTransportationSystem , 1000 ) ;
REGISTER_SHARD_PACKET ( P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION , transportRegisterLocationHandler ) ;
REGISTER_SHARD_PACKET ( P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION , transportWarpHandler ) ;
}