2020-08-18 20:42:30 +00:00
# include "CNShardServer.hpp"
# include "CNStructs.hpp"
# include "ChatManager.hpp"
# include "PlayerManager.hpp"
2020-10-03 15:21:36 +00:00
# include "TransportManager.hpp"
2020-10-03 02:05:20 +00:00
# include "TableData.hpp"
2020-10-07 17:29:59 +00:00
# include "NPCManager.hpp"
# include "MobManager.hpp"
2020-10-18 21:02:51 +00:00
# include "MissionManager.hpp"
2020-11-22 21:29:22 +00:00
# include "ChunkManager.hpp"
2020-08-18 20:42:30 +00:00
2020-10-02 23:50:47 +00:00
# include <sstream>
# include <iterator>
std : : map < std : : string , ChatCommand > ChatManager : : commands ;
std : : vector < std : : string > parseArgs ( std : : string full ) {
std : : stringstream ss ( full ) ;
std : : istream_iterator < std : : string > begin ( ss ) ;
std : : istream_iterator < std : : string > end ;
return std : : vector < std : : string > ( begin , end ) ;
}
2020-10-03 00:20:59 +00:00
bool runCmd ( std : : string full , CNSocket * sock ) {
std : : vector < std : : string > args = parseArgs ( full ) ;
2020-10-02 23:50:47 +00:00
std : : string cmd = args [ 0 ] . substr ( 1 , args [ 0 ] . size ( ) - 1 ) ;
2020-10-05 00:03:13 +00:00
2020-10-02 23:59:07 +00:00
// check if the command exists
2020-10-02 23:50:47 +00:00
if ( ChatManager : : commands . find ( cmd ) ! = ChatManager : : commands . end ( ) ) {
Player * plr = PlayerManager : : getPlayer ( sock ) ;
ChatCommand command = ChatManager : : commands [ cmd ] ;
2020-10-05 00:03:13 +00:00
2020-10-02 23:59:07 +00:00
// sanity check + does the player have the required account level to use the command?
2020-10-02 23:50:47 +00:00
if ( plr ! = nullptr & & plr - > accountLevel < = command . requiredAccLevel ) {
command . handlr ( full , args , sock ) ;
return true ;
} else {
ChatManager : : sendServerMessage ( sock , " You don't have access to that command! " ) ;
return false ;
}
}
ChatManager : : sendServerMessage ( sock , " Unknown command! " ) ;
return false ;
}
2020-10-12 07:08:10 +00:00
void helpCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-10-18 20:43:22 +00:00
ChatManager : : sendServerMessage ( sock , " Commands available to you: " ) ;
2020-10-12 07:08:10 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
for ( auto & cmd : ChatManager : : commands ) {
if ( cmd . second . requiredAccLevel > = plr - > accountId )
ChatManager : : sendServerMessage ( sock , " / " + cmd . first + ( cmd . second . help . length ( ) > 0 ? " - " + cmd . second . help : " " ) ) ;
}
}
2020-10-03 00:20:59 +00:00
void accessCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-10-02 23:50:47 +00:00
ChatManager : : sendServerMessage ( sock , " Your access level is " + std : : to_string ( PlayerManager : : getPlayer ( sock ) - > accountLevel ) ) ;
}
2020-10-05 00:33:30 +00:00
void populationCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
ChatManager : : sendServerMessage ( sock , std : : to_string ( PlayerManager : : players . size ( ) ) + " players online " ) ;
}
void levelCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-10-08 18:20:12 +00:00
if ( args . size ( ) < 2 ) {
ChatManager : : sendServerMessage ( sock , " /level: no level specified " ) ;
return ;
}
2020-10-05 00:33:30 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
if ( plr = = nullptr )
return ;
char * tmp ;
int level = std : : strtol ( args [ 1 ] . c_str ( ) , & tmp , 10 ) ;
if ( * tmp )
return ;
if ( ( level < 1 | | level > 36 ) & & plr - > accountLevel > 30 )
return ;
if ( ! ( level < 1 | | level > 36 ) )
plr - > level = level ;
INITSTRUCT ( sP_FE2CL_REP_PC_CHANGE_LEVEL , resp ) ;
resp . iPC_ID = plr - > iID ;
resp . iPC_Level = level ;
sock - > sendPacket ( ( void * ) & resp , P_FE2CL_REP_PC_CHANGE_LEVEL , sizeof ( sP_FE2CL_REP_PC_CHANGE_LEVEL ) ) ;
PlayerManager : : sendToViewable ( sock , ( void * ) & resp , P_FE2CL_REP_PC_CHANGE_LEVEL , sizeof ( sP_FE2CL_REP_PC_CHANGE_LEVEL ) ) ;
}
2020-10-03 02:05:20 +00:00
void mssCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
if ( args . size ( ) < 2 ) {
ChatManager : : sendServerMessage ( sock , " [MSS] Too few arguments " ) ;
2020-10-03 15:21:36 +00:00
ChatManager : : sendServerMessage ( sock , " [MSS] Usage: /mss <route> <add/remove/goto/clear/test/export> <<height>> " ) ;
2020-10-03 02:05:20 +00:00
return ;
}
// Validate route number
char * routeNumC ;
int routeNum = std : : strtol ( args [ 1 ] . c_str ( ) , & routeNumC , 10 ) ;
if ( * routeNumC ) {
// not an integer
ChatManager : : sendServerMessage ( sock , " [MSS] Invalid route number ' " + args [ 1 ] + " ' " ) ;
return ;
}
if ( args . size ( ) < 3 ) {
ChatManager : : sendServerMessage ( sock , " [MSS] Too few arguments " ) ;
2020-10-06 19:53:21 +00:00
ChatManager : : sendServerMessage ( sock , " [MSS] Usage: /mss <route> <add/remove/goto/clear/test> <<height>> " ) ;
2020-10-03 02:05:20 +00:00
return ;
}
// get the route (if it doesn't exist yet, this will also make it)
2020-10-03 15:21:36 +00:00
std : : vector < WarpLocation > * route = & TableData : : RunningSkywayRoutes [ routeNum ] ;
2020-10-03 02:05:20 +00:00
// mss <route> add <height>
if ( args [ 2 ] = = " add " ) {
// make sure height token exists
if ( args . size ( ) < 4 ) {
ChatManager : : sendServerMessage ( sock , " [MSS] Point height must be specified " ) ;
ChatManager : : sendServerMessage ( sock , " [MSS] Usage: /mss <route> add <height> " ) ;
return ;
}
// validate height token
char * heightC ;
int height = std : : strtol ( args [ 3 ] . c_str ( ) , & heightC , 10 ) ;
if ( * heightC ) {
ChatManager : : sendServerMessage ( sock , " [MSS] Invalid height " + args [ 3 ] ) ;
return ;
}
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-10-03 15:21:36 +00:00
route - > push_back ( { plr - > x , plr - > y , height } ) ; // add point
2020-10-03 02:05:20 +00:00
ChatManager : : sendServerMessage ( sock , " [MSS] Added point ( " + std : : to_string ( plr - > x ) + " , " + std : : to_string ( plr - > y ) + " , " + std : : to_string ( height ) + " ) to route " + std : : to_string ( routeNum ) ) ;
return ;
}
// mss <route> remove
if ( args [ 2 ] = = " remove " ) {
if ( route - > empty ( ) ) {
ChatManager : : sendServerMessage ( sock , " [MSS] Route " + std : : to_string ( routeNum ) + " is empty " ) ;
return ;
}
2020-10-03 15:21:36 +00:00
WarpLocation pulled = route - > back ( ) ;
route - > pop_back ( ) ; // remove point at top of stack
2020-10-03 02:05:20 +00:00
ChatManager : : sendServerMessage ( sock , " [MSS] Removed point ( " + std : : to_string ( pulled . x ) + " , " + std : : to_string ( pulled . y ) + " , " + std : : to_string ( pulled . z ) + " ) from route " + std : : to_string ( routeNum ) ) ;
return ;
}
// mss <route> goto
if ( args [ 2 ] = = " goto " ) {
if ( route - > empty ( ) ) {
ChatManager : : sendServerMessage ( sock , " [MSS] Route " + std : : to_string ( routeNum ) + " is empty " ) ;
return ;
}
2020-10-03 15:21:36 +00:00
WarpLocation pulled = route - > back ( ) ;
PlayerManager : : sendPlayerTo ( sock , pulled . x , pulled . y , pulled . z ) ;
2020-10-03 02:05:20 +00:00
return ;
}
// mss <route> clear
if ( args [ 2 ] = = " clear " ) {
2020-10-03 15:21:36 +00:00
route - > clear ( ) ;
2020-10-03 02:05:20 +00:00
ChatManager : : sendServerMessage ( sock , " [MSS] Cleared route " + std : : to_string ( routeNum ) ) ;
return ;
}
2020-10-06 21:59:33 +00:00
// mss <route> test
2020-10-03 15:21:36 +00:00
if ( args [ 2 ] = = " test " ) {
if ( route - > empty ( ) ) {
ChatManager : : sendServerMessage ( sock , " [MSS] Route " + std : : to_string ( routeNum ) + " is empty " ) ;
return ;
}
2020-10-06 19:53:21 +00:00
WarpLocation pulled = route - > front ( ) ;
PlayerManager : : sendPlayerTo ( sock , pulled . x , pulled . y , pulled . z ) ;
TransportManager : : testMssRoute ( sock , route ) ;
2020-10-03 02:05:20 +00:00
return ;
}
2020-10-06 19:53:21 +00:00
// for compatibility: mss <route> export
2020-10-03 02:05:20 +00:00
if ( args [ 2 ] = = " export " ) {
2020-10-06 21:59:33 +00:00
ChatManager : : sendServerMessage ( sock , " Wrote gruntwork to " + settings : : GRUNTWORKJSON ) ;
2020-10-06 19:53:21 +00:00
TableData : : flush ( ) ;
2020-10-03 02:05:20 +00:00
return ;
}
// mss ????
ChatManager : : sendServerMessage ( sock , " [MSS] Unknown command ' " + args [ 2 ] + " ' " ) ;
2020-10-07 17:29:59 +00:00
}
void summonWCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-10-08 18:20:12 +00:00
if ( args . size ( ) < 2 ) {
2020-10-18 02:13:33 +00:00
ChatManager : : sendServerMessage ( sock , " /summonW: no mob type specified " ) ;
2020-10-08 18:20:12 +00:00
return ;
}
2020-10-07 17:29:59 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
char * rest ;
int type = std : : strtol ( args [ 1 ] . c_str ( ) , & rest , 10 ) ;
if ( * rest ) {
ChatManager : : sendServerMessage ( sock , " Invalid NPC number: " + args [ 1 ] ) ;
return ;
}
// permission & sanity check
if ( plr = = nullptr | | type > = 3314 )
return ;
int team = NPCManager : : NPCData [ type ] [ " m_iTeam " ] ;
assert ( NPCManager : : nextId < INT32_MAX ) ;
2020-10-19 01:45:58 +00:00
# define EXTRA_HEIGHT 200
2020-10-07 17:29:59 +00:00
BaseNPC * npc = nullptr ;
2020-10-19 01:45:58 +00:00
int id = NPCManager : : nextId + + ;
2020-10-07 17:29:59 +00:00
if ( team = = 2 ) {
2020-10-19 01:45:58 +00:00
npc = new Mob ( plr - > x , plr - > y , plr - > z + EXTRA_HEIGHT , plr - > instanceID , type , NPCManager : : NPCData [ type ] , id ) ;
2020-10-07 17:29:59 +00:00
MobManager : : Mobs [ npc - > appearanceData . iNPC_ID ] = ( Mob * ) npc ;
2020-10-03 02:05:20 +00:00
2020-10-07 17:29:59 +00:00
// re-enable respawning
( ( Mob * ) npc ) - > summoned = false ;
} else {
2020-10-19 01:45:58 +00:00
npc = new BaseNPC ( plr - > x , plr - > y , plr - > z + EXTRA_HEIGHT , 0 , plr - > instanceID , type , id ) ;
2020-10-07 17:29:59 +00:00
}
2020-10-19 01:45:58 +00:00
npc - > appearanceData . iAngle = ( plr - > angle + 180 ) % 360 ;
NPCManager : : NPCs [ npc - > appearanceData . iNPC_ID ] = npc ;
2020-11-18 00:07:04 +00:00
NPCManager : : updateNPCPosition ( npc - > appearanceData . iNPC_ID , plr - > x , plr - > y , plr - > z , plr - > instanceID , npc - > appearanceData . iAngle ) ;
2020-10-07 17:29:59 +00:00
2020-10-19 01:45:58 +00:00
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
2020-10-18 20:43:22 +00:00
if ( PLAYERID ( plr - > instanceID ) ! = 0 ) {
2020-10-19 01:45:58 +00:00
id = NPCManager : : nextId + + ;
2020-10-18 02:13:33 +00:00
2020-10-19 01:45:58 +00:00
if ( team = = 2 ) {
npc = new Mob ( plr - > x , plr - > y , plr - > z + EXTRA_HEIGHT , MAPNUM ( plr - > instanceID ) , type , NPCManager : : NPCData [ type ] , id ) ;
2020-10-18 02:13:33 +00:00
2020-10-19 01:45:58 +00:00
MobManager : : Mobs [ npc - > appearanceData . iNPC_ID ] = ( Mob * ) npc ;
( ( Mob * ) npc ) - > summoned = false ;
} else {
npc = new BaseNPC ( plr - > x , plr - > y , plr - > z + EXTRA_HEIGHT , 0 , MAPNUM ( plr - > instanceID ) , type , id ) ;
}
npc - > appearanceData . iAngle = ( plr - > angle + 180 ) % 360 ;
NPCManager : : NPCs [ npc - > appearanceData . iNPC_ID ] = npc ;
2020-10-18 02:13:33 +00:00
2020-11-18 00:07:04 +00:00
NPCManager : : updateNPCPosition ( npc - > appearanceData . iNPC_ID , plr - > x , plr - > y , plr - > z , npc - > instanceID , npc - > appearanceData . iAngle ) ;
2020-10-18 02:13:33 +00:00
}
2020-10-07 17:29:59 +00:00
ChatManager : : sendServerMessage ( sock , " /summonW: placed mob with type: " + std : : to_string ( type ) +
" , id: " + std : : to_string ( npc - > appearanceData . iNPC_ID ) ) ;
2020-10-18 02:13:33 +00:00
TableData : : RunningMobs [ npc - > appearanceData . iNPC_ID ] = npc ; // only record the one in the template
2020-10-03 02:05:20 +00:00
}
2020-10-07 17:29:59 +00:00
void unsummonWCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-11-17 23:16:16 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-10-06 22:34:11 +00:00
2020-11-23 00:14:46 +00:00
BaseNPC * npc = NPCManager : : getNearestNPC ( plr - > viewableChunks , plr - > x , plr - > y , plr - > z ) ;
2020-10-07 17:29:59 +00:00
if ( npc = = nullptr ) {
ChatManager : : sendServerMessage ( sock , " /unsummonW: No NPCs found nearby " ) ;
return ;
}
2020-11-08 08:42:49 +00:00
if ( TableData : : RunningEggs . find ( npc - > appearanceData . iNPC_ID ) ! = TableData : : RunningEggs . end ( ) ) {
ChatManager : : sendServerMessage ( sock , " /unsummonW: removed egg with type: " + std : : to_string ( npc - > appearanceData . iNPCType ) +
" , id: " + std : : to_string ( npc - > appearanceData . iNPC_ID ) ) ;
TableData : : RunningEggs . erase ( npc - > appearanceData . iNPC_ID ) ;
NPCManager : : destroyNPC ( npc - > appearanceData . iNPC_ID ) ;
return ;
}
2020-10-07 17:29:59 +00:00
if ( TableData : : RunningMobs . find ( npc - > appearanceData . iNPC_ID ) = = TableData : : RunningMobs . end ( ) ) {
ChatManager : : sendServerMessage ( sock , " /unsummonW: Closest NPC is not a gruntwork mob. " ) ;
return ;
}
2020-11-16 03:13:40 +00:00
int leadId = ( ( Mob * ) npc ) - > groupLeader ;
if ( leadId ! = 0 ) {
2020-11-23 00:14:46 +00:00
if ( MobManager : : Mobs . find ( leadId ) = = MobManager : : Mobs . end ( ) ) {
std : : cout < < " [WARN] unsummonW: leader not found! " < < std : : endl ;
}
2020-11-16 03:13:40 +00:00
Mob * leadNpc = MobManager : : Mobs [ leadId ] ;
for ( int i = 0 ; i < 4 ; i + + ) {
if ( leadNpc - > groupMember [ i ] = = 0 )
break ;
2020-11-23 00:14:46 +00:00
if ( MobManager : : Mobs . find ( leadNpc - > groupMember [ i ] ) = = MobManager : : Mobs . end ( ) ) {
std : : cout < < " [WARN] unsommonW: leader can't find a group member! " < < std : : endl ;
continue ;
}
2020-11-16 03:13:40 +00:00
TableData : : RunningMobs . erase ( leadNpc - > groupMember [ i ] ) ;
NPCManager : : destroyNPC ( leadNpc - > groupMember [ i ] ) ;
}
TableData : : RunningMobs . erase ( leadId ) ;
NPCManager : : destroyNPC ( leadId ) ;
ChatManager : : sendServerMessage ( sock , " /unsummonW: Mob group destroyed. " ) ;
return ;
}
2020-10-07 17:29:59 +00:00
ChatManager : : sendServerMessage ( sock , " /unsummonW: removed mob with type: " + std : : to_string ( npc - > appearanceData . iNPCType ) +
" , id: " + std : : to_string ( npc - > appearanceData . iNPC_ID ) ) ;
TableData : : RunningMobs . erase ( npc - > appearanceData . iNPC_ID ) ;
NPCManager : : destroyNPC ( npc - > appearanceData . iNPC_ID ) ;
}
2020-10-07 18:38:32 +00:00
void toggleAiCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
MobManager : : simulateMobs = ! MobManager : : simulateMobs ;
if ( MobManager : : simulateMobs )
return ;
// return all mobs to their spawn points
for ( auto & pair : MobManager : : Mobs ) {
pair . second - > state = MobState : : RETREAT ;
pair . second - > target = nullptr ;
2020-10-14 21:15:02 +00:00
pair . second - > nextMovement = getTime ( ) ;
2020-10-13 19:44:43 +00:00
2020-10-14 21:15:02 +00:00
// mobs with static paths can chill where they are
if ( pair . second - > staticPath ) {
pair . second - > roamX = pair . second - > appearanceData . iX ;
pair . second - > roamY = pair . second - > appearanceData . iY ;
pair . second - > roamZ = pair . second - > appearanceData . iZ ;
} else {
pair . second - > roamX = pair . second - > spawnX ;
pair . second - > roamY = pair . second - > spawnY ;
pair . second - > roamZ = pair . second - > spawnZ ;
}
2020-10-07 18:38:32 +00:00
}
}
2020-10-07 17:29:59 +00:00
void npcRotateCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-11-17 23:16:16 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-10-19 17:26:14 +00:00
2020-11-23 00:14:46 +00:00
BaseNPC * npc = NPCManager : : getNearestNPC ( plr - > viewableChunks , plr - > x , plr - > y , plr - > z ) ;
2020-10-06 21:59:33 +00:00
2020-10-06 22:34:11 +00:00
if ( npc = = nullptr ) {
ChatManager : : sendServerMessage ( sock , " [NPCR] No NPCs found nearby " ) ;
2020-10-06 21:59:33 +00:00
return ;
}
2020-10-06 22:34:11 +00:00
int angle = ( plr - > angle + 180 ) % 360 ;
2020-11-18 00:07:04 +00:00
NPCManager : : updateNPCPosition ( npc - > appearanceData . iNPC_ID , npc - > appearanceData . iX , npc - > appearanceData . iY , npc - > appearanceData . iZ , npc - > instanceID , angle ) ;
2020-10-19 01:45:58 +00:00
// if it's a gruntwork NPC, rotate in-place
if ( TableData : : RunningMobs . find ( npc - > appearanceData . iNPC_ID ) ! = TableData : : RunningMobs . end ( ) ) {
2020-11-18 00:07:04 +00:00
NPCManager : : updateNPCPosition ( npc - > appearanceData . iNPC_ID , npc - > appearanceData . iX , npc - > appearanceData . iY , npc - > appearanceData . iZ , npc - > instanceID , angle ) ;
2020-10-19 01:45:58 +00:00
ChatManager : : sendServerMessage ( sock , " [NPCR] Successfully set angle to " + std : : to_string ( angle ) + " for gruntwork NPC "
+ std : : to_string ( npc - > appearanceData . iNPC_ID ) ) ;
} else {
TableData : : RunningNPCRotations [ npc - > appearanceData . iNPC_ID ] = angle ;
ChatManager : : sendServerMessage ( sock , " [NPCR] Successfully set angle to " + std : : to_string ( angle ) + " for NPC "
+ std : : to_string ( npc - > appearanceData . iNPC_ID ) ) ;
}
2020-10-06 22:34:11 +00:00
// update rotation clientside
INITSTRUCT ( sP_FE2CL_NPC_ENTER , pkt ) ;
pkt . NPCAppearanceData = npc - > appearanceData ;
sock - > sendPacket ( ( void * ) & pkt , P_FE2CL_NPC_ENTER , sizeof ( sP_FE2CL_NPC_ENTER ) ) ;
2020-10-06 21:59:33 +00:00
}
2020-10-06 22:00:17 +00:00
void refreshCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-11-22 21:29:22 +00:00
ChunkPos currentChunk = plr - > chunkPos ;
ChunkPos nullChunk = std : : make_tuple ( 0 , 0 , 0 ) ;
ChunkManager : : updatePlayerChunk ( sock , currentChunk , nullChunk ) ;
ChunkManager : : updatePlayerChunk ( sock , nullChunk , currentChunk ) ;
2020-10-06 22:00:17 +00:00
}
2020-10-12 01:53:01 +00:00
void instanceCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
Player * plr = PlayerManager : : getPlayer ( sock ) ;
// no additional arguments: report current instance ID
if ( args . size ( ) < 2 ) {
ChatManager : : sendServerMessage ( sock , " [INST] Current instance ID: " + std : : to_string ( plr - > instanceID ) ) ;
2020-10-18 20:43:22 +00:00
ChatManager : : sendServerMessage ( sock , " [INST] (Map " + std : : to_string ( MAPNUM ( plr - > instanceID ) ) + " , instance " + std : : to_string ( PLAYERID ( plr - > instanceID ) ) + " ) " ) ;
2020-10-12 01:53:01 +00:00
return ;
}
// move player to specified instance
// validate instance ID
char * instanceS ;
int instance = std : : strtol ( args [ 1 ] . c_str ( ) , & instanceS , 10 ) ;
if ( * instanceS ) {
ChatManager : : sendServerMessage ( sock , " [INST] Invalid instance ID: " + args [ 1 ] ) ;
return ;
}
PlayerManager : : sendPlayerTo ( sock , plr - > x , plr - > y , plr - > z , instance ) ;
ChatManager : : sendServerMessage ( sock , " [INST] Switched to instance with ID " + std : : to_string ( instance ) ) ;
}
void npcInstanceCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-11-17 23:16:16 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-10-12 01:53:01 +00:00
if ( args . size ( ) < 2 ) {
ChatManager : : sendServerMessage ( sock , " [NPCI] Instance ID must be specified " ) ;
ChatManager : : sendServerMessage ( sock , " [NPCI] Usage: /npci <instance ID> " ) ;
return ;
}
2020-11-23 00:14:46 +00:00
BaseNPC * npc = NPCManager : : getNearestNPC ( plr - > viewableChunks , plr - > x , plr - > y , plr - > z ) ;
2020-10-12 01:53:01 +00:00
if ( npc = = nullptr ) {
ChatManager : : sendServerMessage ( sock , " [NPCI] No NPCs found nearby " ) ;
return ;
}
// validate instance ID
char * instanceS ;
int instance = std : : strtol ( args [ 1 ] . c_str ( ) , & instanceS , 10 ) ;
if ( * instanceS ) {
ChatManager : : sendServerMessage ( sock , " [NPCI] Invalid instance ID: " + args [ 1 ] ) ;
return ;
}
ChatManager : : sendServerMessage ( sock , " [NPCI] Moving NPC with ID " + std : : to_string ( npc - > appearanceData . iNPC_ID ) + " to instance " + std : : to_string ( instance ) ) ;
TableData : : RunningNPCMapNumbers [ npc - > appearanceData . iNPC_ID ] = instance ;
2020-11-18 00:07:04 +00:00
NPCManager : : updateNPCPosition ( npc - > appearanceData . iNPC_ID , npc - > appearanceData . iX , npc - > appearanceData . iY , npc - > appearanceData . iZ , instance , npc - > appearanceData . iAngle ) ;
2020-10-12 01:53:01 +00:00
}
2020-10-18 21:02:51 +00:00
void minfoCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
Player * plr = PlayerManager : : getPlayer ( sock ) ;
ChatManager : : sendServerMessage ( sock , " [MINFO] Current mission ID: " + std : : to_string ( plr - > CurrentMissionID ) ) ;
for ( int i = 0 ; i < ACTIVE_MISSION_COUNT ; i + + ) {
if ( plr - > tasks [ i ] ! = 0 ) {
TaskData & task = * MissionManager : : Tasks [ plr - > tasks [ i ] ] ;
if ( ( int ) ( task [ " m_iHMissionID " ] ) = = plr - > CurrentMissionID ) {
ChatManager : : sendServerMessage ( sock , " [MINFO] Current task ID: " + std : : to_string ( plr - > tasks [ i ] ) ) ;
ChatManager : : sendServerMessage ( sock , " [MINFO] Current task type: " + std : : to_string ( ( int ) ( task [ " m_iHTaskType " ] ) ) ) ;
ChatManager : : sendServerMessage ( sock , " [MINFO] Current waypoint NPC ID: " + std : : to_string ( ( int ) ( task [ " m_iSTGrantWayPoint " ] ) ) ) ;
2020-10-21 05:24:51 +00:00
ChatManager : : sendServerMessage ( sock , " [MINFO] Current terminator NPC ID: " + std : : to_string ( ( int ) ( task [ " m_iHTerminatorNPCID " ] ) ) ) ;
2020-10-18 21:02:51 +00:00
for ( int j = 0 ; j < 3 ; j + + )
if ( ( int ) ( task [ " m_iCSUEnemyID " ] [ j ] ) ! = 0 )
ChatManager : : sendServerMessage ( sock , " [MINFO] Current task mob # " + std : : to_string ( j + 1 ) + " : " + std : : to_string ( ( int ) ( task [ " m_iCSUEnemyID " ] [ j ] ) ) ) ;
return ;
}
}
}
}
void tasksCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
Player * plr = PlayerManager : : getPlayer ( sock ) ;
for ( int i = 0 ; i < ACTIVE_MISSION_COUNT ; i + + ) {
if ( plr - > tasks [ i ] ! = 0 ) {
TaskData & task = * MissionManager : : Tasks [ plr - > tasks [ i ] ] ;
ChatManager : : sendServerMessage ( sock , " [TASK- " + std : : to_string ( i ) + " ] mission ID: " + std : : to_string ( ( int ) ( task [ " m_iHMissionID " ] ) ) ) ;
ChatManager : : sendServerMessage ( sock , " [TASK- " + std : : to_string ( i ) + " ] task ID: " + std : : to_string ( plr - > tasks [ i ] ) ) ;
}
}
}
2020-10-22 08:23:12 +00:00
void buffCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
if ( args . size ( ) < 3 ) {
ChatManager : : sendServerMessage ( sock , " /buff: no skill Id and duration time specified " ) ;
return ;
}
char * tmp ;
int skillId = std : : strtol ( args [ 1 ] . c_str ( ) , & tmp , 10 ) ;
if ( * tmp )
return ;
int duration = std : : strtol ( args [ 2 ] . c_str ( ) , & tmp , 10 ) ;
if ( * tmp )
return ;
if ( NPCManager : : eggBuffPlayer ( sock , skillId , duration ) < 0 )
ChatManager : : sendServerMessage ( sock , " /buff: unknown skill Id " ) ;
}
2020-11-09 10:04:30 +00:00
void eggCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
if ( args . size ( ) < 2 ) {
ChatManager : : sendServerMessage ( sock , " /egg: no egg type specified " ) ;
return ;
}
char * tmp ;
int eggType = std : : strtol ( args [ 1 ] . c_str ( ) , & tmp , 10 ) ;
if ( * tmp )
return ;
if ( NPCManager : : EggTypes . find ( eggType ) = = NPCManager : : EggTypes . end ( ) ) {
ChatManager : : sendServerMessage ( sock , " /egg: Unknown egg type " ) ;
return ;
}
assert ( NPCManager : : nextId < INT32_MAX ) ;
int id = NPCManager : : nextId + + ;
Player * plr = PlayerManager : : getPlayer ( sock ) ;
if ( plr = = nullptr )
return ;
// some math to place egg nicely in front of the player
// temporarly disabled for sake of gruntwork
int addX = 0 ; //-500.0f * sin(plr->angle / 180.0f * M_PI);
int addY = 0 ; //-500.0f * cos(plr->angle / 180.0f * M_PI);
Egg * egg = new Egg ( plr - > x + addX , plr - > y + addY , plr - > z , plr - > instanceID , eggType , id , false ) ; // change last arg to true after gruntwork
NPCManager : : NPCs [ id ] = egg ;
NPCManager : : Eggs [ id ] = egg ;
2020-11-18 00:07:04 +00:00
NPCManager : : updateNPCPosition ( id , plr - > x + addX , plr - > y + addY , plr - > z , plr - > instanceID , plr - > angle ) ;
2020-11-09 10:04:30 +00:00
// add to template
TableData : : RunningEggs [ id ] = egg ;
}
2020-10-31 17:12:13 +00:00
void notifyCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
Player * plr = PlayerManager : : getPlayer ( sock ) ;
if ( plr - > notify ) {
2020-11-16 03:13:40 +00:00
plr - > notify = false ;
ChatManager : : sendServerMessage ( sock , " [ADMIN] No longer receiving join notifications " ) ;
2020-10-31 17:12:13 +00:00
} else {
2020-11-16 03:13:40 +00:00
plr - > notify = true ;
ChatManager : : sendServerMessage ( sock , " [ADMIN] Receiving join notifications " ) ;
2020-10-31 17:12:13 +00:00
}
}
void playersCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
ChatManager : : sendServerMessage ( sock , " [ADMIN] Players on the server: " ) ;
for ( auto pair : PlayerManager : : players )
2020-11-17 23:16:16 +00:00
ChatManager : : sendServerMessage ( sock , PlayerManager : : getPlayerName ( pair . second ) ) ;
2020-10-31 17:12:13 +00:00
}
2020-11-16 03:13:40 +00:00
void summonGroupCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
2020-11-15 18:19:34 +00:00
if ( args . size ( ) < 4 ) {
2020-11-16 03:13:40 +00:00
ChatManager : : sendServerMessage ( sock , " /summonGroup(W) <leadermob> <mob> <number> [distance] " ) ;
2020-11-15 18:19:34 +00:00
return ;
}
Player * plr = PlayerManager : : getPlayer ( sock ) ;
char * rest ;
2020-11-16 03:13:40 +00:00
bool wCommand = ( args [ 0 ] = = " /summonGroupW " ) ;
2020-11-15 18:19:34 +00:00
int type = std : : strtol ( args [ 1 ] . c_str ( ) , & rest , 10 ) ;
int type2 = std : : strtol ( args [ 2 ] . c_str ( ) , & rest , 10 ) ;
int count = std : : strtol ( args [ 3 ] . c_str ( ) , & rest , 10 ) ;
int distance = 150 ;
if ( args . size ( ) > 4 )
distance = std : : strtol ( args [ 4 ] . c_str ( ) , & rest , 10 ) ;
if ( * rest ) {
ChatManager : : sendServerMessage ( sock , " Invalid NPC number: " + args [ 1 ] ) ;
return ;
}
// permission & sanity check
2020-11-23 00:14:46 +00:00
if ( type > = 3314 | | type2 > = 3314 | | count > 5 ) {
ChatManager : : sendServerMessage ( sock , " Invalid parameters; double check types and count " ) ;
2020-11-15 18:19:34 +00:00
return ;
2020-11-23 00:14:46 +00:00
}
2020-11-15 18:19:34 +00:00
Mob * leadNpc = nullptr ;
for ( int i = 0 ; i < count ; i + + ) {
int team = NPCManager : : NPCData [ type ] [ " m_iTeam " ] ;
assert ( NPCManager : : nextId < INT32_MAX ) ;
# define EXTRA_HEIGHT 200
BaseNPC * npc = nullptr ;
int id = NPCManager : : nextId + + ;
int x = plr - > x ;
int y = plr - > y ;
int z = plr - > z ;
if ( i > 0 ) {
int angle = 360.0f / ( count - 1 ) * ( i - 1 ) ;
if ( count = = 3 )
angle = 90 + 60 * i ;
angle + = ( plr - > angle + 180 ) % 360 ;
x + = - 1.0f * sin ( angle / 180.0f * M_PI ) * distance ;
y + = - 1.0f * cos ( angle / 180.0f * M_PI ) * distance ;
z = plr - > z ;
}
if ( team = = 2 ) {
npc = new Mob ( x , y , z + EXTRA_HEIGHT , plr - > instanceID , type , NPCManager : : NPCData [ type ] , id ) ;
MobManager : : Mobs [ npc - > appearanceData . iNPC_ID ] = ( Mob * ) npc ;
if ( i > 0 ) {
leadNpc - > groupMember [ i - 1 ] = npc - > appearanceData . iNPC_ID ;
Mob * mob = MobManager : : Mobs [ npc - > appearanceData . iNPC_ID ] ;
mob - > groupLeader = leadNpc - > appearanceData . iNPC_ID ;
mob - > offsetX = x - plr - > x ;
mob - > offsetY = y - plr - > y ;
}
// re-enable respawning
2020-11-16 03:13:40 +00:00
if ( wCommand )
( ( Mob * ) npc ) - > summoned = false ;
2020-11-15 18:19:34 +00:00
} else {
npc = new BaseNPC ( x , y , z + EXTRA_HEIGHT , 0 , plr - > instanceID , type , id ) ;
}
npc - > appearanceData . iAngle = ( plr - > angle + 180 ) % 360 ;
NPCManager : : NPCs [ npc - > appearanceData . iNPC_ID ] = npc ;
2020-11-23 00:14:46 +00:00
NPCManager : : updateNPCPosition ( npc - > appearanceData . iNPC_ID , x , y , z , plr - > instanceID , npc - > appearanceData . iAngle ) ;
2020-11-15 18:19:34 +00:00
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
if ( PLAYERID ( plr - > instanceID ) ! = 0 ) {
id = NPCManager : : nextId + + ;
if ( team = = 2 ) {
npc = new Mob ( x , y , z + EXTRA_HEIGHT , MAPNUM ( plr - > instanceID ) , type , NPCManager : : NPCData [ type ] , id ) ;
MobManager : : Mobs [ npc - > appearanceData . iNPC_ID ] = ( Mob * ) npc ;
if ( i > 0 ) {
leadNpc - > groupMember [ i - 1 ] = npc - > appearanceData . iNPC_ID ;
Mob * mob = MobManager : : Mobs [ npc - > appearanceData . iNPC_ID ] ;
mob - > groupLeader = leadNpc - > appearanceData . iNPC_ID ;
mob - > offsetX = x - plr - > x ;
mob - > offsetY = y - plr - > y ;
}
2020-11-16 03:13:40 +00:00
if ( wCommand )
( ( Mob * ) npc ) - > summoned = false ;
2020-11-15 18:19:34 +00:00
} else {
npc = new BaseNPC ( x , y , z + EXTRA_HEIGHT , 0 , MAPNUM ( plr - > instanceID ) , type , id ) ;
}
npc - > appearanceData . iAngle = ( plr - > angle + 180 ) % 360 ;
NPCManager : : NPCs [ npc - > appearanceData . iNPC_ID ] = npc ;
2020-11-23 00:14:46 +00:00
NPCManager : : updateNPCPosition ( npc - > appearanceData . iNPC_ID , x , y , z , plr - > instanceID , npc - > appearanceData . iAngle ) ;
2020-11-15 18:19:34 +00:00
}
2020-11-16 03:13:40 +00:00
ChatManager : : sendServerMessage ( sock , " /summonGroup(W): placed mob with type: " + std : : to_string ( type ) +
2020-11-15 18:19:34 +00:00
" , id: " + std : : to_string ( npc - > appearanceData . iNPC_ID ) ) ;
2020-11-16 03:13:40 +00:00
if ( wCommand )
TableData : : RunningMobs [ npc - > appearanceData . iNPC_ID ] = npc ; // only record the one in the template
2020-11-15 18:19:34 +00:00
if ( i = = 0 & & team = = 2 ) {
type = type2 ;
leadNpc = MobManager : : Mobs [ npc - > appearanceData . iNPC_ID ] ;
leadNpc - > groupLeader = leadNpc - > appearanceData . iNPC_ID ;
}
}
}
2020-10-06 19:53:21 +00:00
void flushCommand ( std : : string full , std : : vector < std : : string > & args , CNSocket * sock ) {
TableData : : flush ( ) ;
2020-10-07 17:29:59 +00:00
ChatManager : : sendServerMessage ( sock , " Wrote gruntwork to " + settings : : GRUNTWORKJSON ) ;
2020-10-06 19:53:21 +00:00
}
2020-08-18 20:42:30 +00:00
void ChatManager : : init ( ) {
REGISTER_SHARD_PACKET ( P_CL2FE_REQ_SEND_FREECHAT_MESSAGE , chatHandler ) ;
REGISTER_SHARD_PACKET ( P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT , emoteHandler ) ;
2020-08-22 18:11:47 +00:00
REGISTER_SHARD_PACKET ( P_CL2FE_REQ_SEND_MENUCHAT_MESSAGE , menuChatHandler ) ;
2020-11-19 16:19:22 +00:00
REGISTER_SHARD_PACKET ( P_CL2FE_GM_REQ_PC_ANNOUNCE , announcementHandler ) ;
2020-10-02 23:50:47 +00:00
2020-10-18 20:43:22 +00:00
registerCommand ( " help " , 100 , helpCommand , " list all unlocked server-side commands " ) ;
registerCommand ( " access " , 100 , accessCommand , " print your access level " ) ;
registerCommand ( " instance " , 30 , instanceCommand , " print or change your current instance " ) ;
registerCommand ( " mss " , 30 , mssCommand , " edit Monkey Skyway routes " ) ;
registerCommand ( " npcr " , 30 , npcRotateCommand , " rotate NPCs " ) ;
registerCommand ( " npci " , 30 , npcInstanceCommand , " move NPCs across instances " ) ;
registerCommand ( " summonW " , 30 , summonWCommand , " permanently summon NPCs " ) ;
registerCommand ( " unsummonW " , 30 , unsummonWCommand , " delete permanently summoned NPCs " ) ;
registerCommand ( " toggleai " , 30 , toggleAiCommand , " enable/disable mob AI " ) ;
registerCommand ( " flush " , 30 , flushCommand , " save gruntwork to file " ) ;
registerCommand ( " level " , 50 , levelCommand , " change your character's level " ) ;
registerCommand ( " population " , 100 , populationCommand , " check how many players are online " ) ;
registerCommand ( " refresh " , 100 , refreshCommand , " teleport yourself to your current location " ) ;
2020-10-18 21:02:51 +00:00
registerCommand ( " minfo " , 30 , minfoCommand , " show details of the current mission and task. " ) ;
2020-10-22 08:23:12 +00:00
registerCommand ( " buff " , 50 , buffCommand , " give yourself a buff effect " ) ;
2020-11-09 10:04:30 +00:00
registerCommand ( " egg " , 30 , eggCommand , " summon a coco egg " ) ;
2020-10-18 21:02:51 +00:00
registerCommand ( " tasks " , 30 , tasksCommand , " list all active missions and their respective task ids. " ) ;
2020-10-31 17:12:13 +00:00
registerCommand ( " notify " , 30 , notifyCommand , " receive a message whenever a player joins the server " ) ;
registerCommand ( " players " , 30 , playersCommand , " print all players on the server " ) ;
2020-11-16 03:13:40 +00:00
registerCommand ( " summonGroup " , 30 , summonGroupCommand , " summon group NPCs " ) ;
registerCommand ( " summonGroupW " , 30 , summonGroupCommand , " permanently summon group NPCs " ) ;
2020-10-02 23:50:47 +00:00
}
2020-10-12 07:08:10 +00:00
void ChatManager : : registerCommand ( std : : string cmd , int requiredLevel , CommandHandler handlr , std : : string help ) {
commands [ cmd ] = ChatCommand ( requiredLevel , handlr , help ) ;
2020-08-18 20:42:30 +00:00
}
void ChatManager : : chatHandler ( CNSocket * sock , CNPacketData * data ) {
2020-08-20 23:50:30 +00:00
if ( data - > size ! = sizeof ( sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE ) )
return ; // malformed packet
2020-10-05 00:03:13 +00:00
2020-08-18 20:42:30 +00:00
sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE * chat = ( sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE * ) data - > buf ;
2020-10-02 23:50:47 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-10-31 20:31:25 +00:00
std : : string fullChat = sanitizeText ( U16toU8 ( chat - > szFreeChat ) ) ;
std : : cout < < " [FreeChat] " < < PlayerManager : : getPlayerName ( plr , false ) < < " : " < < fullChat < < std : : endl ;
2020-10-02 23:50:47 +00:00
2020-10-03 00:20:59 +00:00
if ( fullChat . length ( ) > 1 & & fullChat [ 0 ] = = CMD_PREFIX ) { // PREFIX
runCmd ( fullChat , sock ) ;
2020-10-02 23:50:47 +00:00
return ;
}
2020-08-19 18:22:51 +00:00
2020-08-19 18:25:54 +00:00
// send to client
2020-08-23 00:26:18 +00:00
INITSTRUCT ( sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC , resp ) ;
2020-10-31 20:31:25 +00:00
U8toU16 ( fullChat , ( char16_t * ) & resp . szFreeChat , sizeof ( resp . szFreeChat ) ) ;
2020-10-02 23:50:47 +00:00
resp . iPC_ID = plr - > iID ;
2020-08-22 23:31:09 +00:00
resp . iEmoteCode = chat - > iEmoteCode ;
2020-10-31 20:31:25 +00:00
2020-08-22 23:31:09 +00:00
sock - > sendPacket ( ( void * ) & resp , P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC , sizeof ( sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC ) ) ;
2020-08-19 18:22:51 +00:00
2020-08-19 18:25:54 +00:00
// send to visible players
2020-09-17 22:45:43 +00:00
PlayerManager : : sendToViewable ( sock , ( void * ) & resp , P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC , sizeof ( sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC ) ) ;
2020-08-18 20:42:30 +00:00
}
2020-09-16 19:46:15 +00:00
2020-08-22 18:11:47 +00:00
void ChatManager : : menuChatHandler ( CNSocket * sock , CNPacketData * data ) {
if ( data - > size ! = sizeof ( sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE ) )
return ; // malformed packet
2020-10-31 20:31:25 +00:00
2020-08-22 18:11:47 +00:00
sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE * chat = ( sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE * ) data - > buf ;
2020-10-31 20:31:25 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
std : : string fullChat = sanitizeText ( U16toU8 ( chat - > szFreeChat ) ) ;
std : : cout < < " [MenuChat] " < < PlayerManager : : getPlayerName ( plr , false ) < < " : " < < fullChat < < std : : endl ;
2020-08-22 18:11:47 +00:00
// send to client
2020-08-23 00:26:18 +00:00
INITSTRUCT ( sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC , resp ) ;
2020-10-31 20:31:25 +00:00
U8toU16 ( fullChat , ( char16_t * ) & resp . szFreeChat , sizeof ( resp . szFreeChat ) ) ;
2020-11-17 23:16:16 +00:00
resp . iPC_ID = PlayerManager : : getPlayer ( sock ) - > iID ;
2020-08-22 23:31:09 +00:00
resp . iEmoteCode = chat - > iEmoteCode ;
2020-10-31 20:31:25 +00:00
2020-08-22 23:31:09 +00:00
sock - > sendPacket ( ( void * ) & resp , P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC , sizeof ( sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC ) ) ;
2020-08-18 20:42:30 +00:00
2020-08-22 18:11:47 +00:00
// send to visible players
2020-09-17 22:45:43 +00:00
PlayerManager : : sendToViewable ( sock , ( void * ) & resp , P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC , sizeof ( sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC ) ) ;
2020-08-22 18:11:47 +00:00
}
2020-09-16 19:46:15 +00:00
2020-08-18 20:42:30 +00:00
void ChatManager : : emoteHandler ( CNSocket * sock , CNPacketData * data ) {
2020-08-19 00:11:31 +00:00
if ( data - > size ! = sizeof ( sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT ) )
return ; // ignore the malformed packet
2020-08-18 20:42:30 +00:00
// you can dance with friends!!!!!!!!
sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT * emote = ( sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT * ) data - > buf ;
2020-10-02 23:50:47 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
2020-09-14 13:53:48 +00:00
2020-08-18 20:42:30 +00:00
// send to client
2020-08-23 00:26:18 +00:00
INITSTRUCT ( sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT , resp ) ;
2020-08-22 23:31:09 +00:00
resp . iEmoteCode = emote - > iEmoteCode ;
2020-10-02 23:50:47 +00:00
resp . iID_From = plr - > iID ;
2020-08-22 23:31:09 +00:00
sock - > sendPacket ( ( void * ) & resp , P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT , sizeof ( sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT ) ) ;
2020-08-18 20:42:30 +00:00
// send to visible players (players within render distance)
2020-09-17 22:45:43 +00:00
PlayerManager : : sendToViewable ( sock , ( void * ) & resp , P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT , sizeof ( sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT ) ) ;
2020-08-18 20:42:30 +00:00
}
2020-10-02 23:50:47 +00:00
void ChatManager : : sendServerMessage ( CNSocket * sock , std : : string msg ) {
INITSTRUCT ( sP_FE2CL_PC_MOTD_LOGIN , motd ) ;
motd . iType = 1 ;
2020-10-04 17:52:16 +00:00
// convert string to u16 and write it to the buffer
2020-10-04 17:50:58 +00:00
U8toU16 ( msg , ( char16_t * ) motd . szSystemMsg , sizeof ( motd . szSystemMsg ) ) ;
2020-10-02 23:50:47 +00:00
// send the packet :)
sock - > sendPacket ( ( void * ) & motd , P_FE2CL_PC_MOTD_LOGIN , sizeof ( sP_FE2CL_PC_MOTD_LOGIN ) ) ;
}
2020-10-31 20:31:25 +00:00
2020-11-19 16:19:22 +00:00
void ChatManager : : announcementHandler ( CNSocket * sock , CNPacketData * data ) {
if ( data - > size ! = sizeof ( sP_CL2FE_GM_REQ_PC_ANNOUNCE ) )
return ; // ignore malformed packet
2020-11-17 23:16:16 +00:00
Player * plr = PlayerManager : : getPlayer ( sock ) ;
if ( plr - > accountLevel > 30 )
2020-11-19 16:19:22 +00:00
return ; // only players with account level less than 30 (GM) are allowed to use this command
sP_CL2FE_GM_REQ_PC_ANNOUNCE * announcement = ( sP_CL2FE_GM_REQ_PC_ANNOUNCE * ) data - > buf ;
INITSTRUCT ( sP_FE2CL_GM_REP_PC_ANNOUNCE , msg ) ;
msg . iAnnounceType = announcement - > iAnnounceType ;
msg . iDuringTime = announcement - > iDuringTime ;
memcpy ( msg . szAnnounceMsg , announcement - > szAnnounceMsg , sizeof ( msg . szAnnounceMsg ) ) ;
2020-11-17 23:16:16 +00:00
std : : map < CNSocket * , Player * > : : iterator it ;
2020-11-19 16:19:22 +00:00
switch ( announcement - > iAreaType ) {
2020-11-17 23:16:16 +00:00
case 0 : // area (all players in viewable chunks)
PlayerManager : : sendToViewable ( sock , ( void * ) & msg , P_FE2CL_GM_REP_PC_ANNOUNCE , sizeof ( sP_FE2CL_GM_REP_PC_ANNOUNCE ) ) ;
break ;
2020-11-19 16:19:22 +00:00
case 1 : // shard
break ; //stubbed for now
case 2 : // world
break ; // stubbed for now
2020-11-17 23:16:16 +00:00
case 3 : // global (all players)
2020-11-19 16:19:22 +00:00
for ( it = PlayerManager : : players . begin ( ) ; it ! = PlayerManager : : players . end ( ) ; it + + ) {
CNSocket * allSock = it - > first ;
allSock - > sendPacket ( ( void * ) & msg , P_FE2CL_GM_REP_PC_ANNOUNCE , sizeof ( sP_FE2CL_GM_REP_PC_ANNOUNCE ) ) ;
}
default :
break ;
}
}
2020-10-31 20:31:25 +00:00
// we only allow plain ascii, at least for now
std : : string ChatManager : : sanitizeText ( std : : string text ) {
int i ;
char buf [ 128 ] ;
i = 0 ;
for ( char c : text ) {
if ( i > = 127 )
break ;
if ( c > = ' ' & & c < = ' ~ ' )
buf [ i + + ] = c ;
}
buf [ i ] = 0 ;
return std : : string ( buf ) ;
}