2016-02-11 22:54:43 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
* - 2005/11/25 MuadDib: Added PKTBI_BF::TYPE_SESPAM: to do away with spam.
|
|
|
|
|
* - 2005/11/23 MuadDib: Altered handle_mode_set for 0x72 Packet. Nows reads
|
|
|
|
|
* from combat.cfg for warmode_wait object. Sends the
|
|
|
|
|
* 0x77 Packet and returns 0 when out of timer.
|
|
|
|
|
* - 2005/12/09 MuadDib: Added TYPE_CLIENT_LANGUAGE for setting member uclang.
|
|
|
|
|
* - 2006/05/24 Shinigami: Added PKTBI_BF::TYPE_CHARACTER_RACE_CHANGER to support Elfs
|
|
|
|
|
* - 2006/05/30 Shinigami: Changed params of character_race_changer_handler()
|
|
|
|
|
* - 2009/07/23 MuadDib: updates for new Enum::Packet IDs
|
|
|
|
|
* - 2009/08/14 Turley: Added PKTBI_BF::TYPE_SCREEN_SIZE & TYPE_CLOSED_STATUS_GUMP (anti spam)
|
|
|
|
|
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
|
|
|
|
|
* - 2009/09/03 MuadDib: Relocation of multi related cpp/h
|
|
|
|
|
* - 2009/09/06 Turley: Changed Version checks to bitfield client->ClientType
|
|
|
|
|
* Added 0xE1 packet (UO3D clienttype packet)
|
|
|
|
|
* - 2009/11/19 Turley: ssopt.core_sends_season & .core_handled_tags - Tomi
|
|
|
|
|
* - 2009/12/03 Turley: toggle gargoyle flying support
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
/* MISCMSG.CPP: Miscellaneous message handlers. Handlers shouldn't stay here long,
|
2016-02-11 22:54:43 +01:00
|
|
|
only until they find a better home - but this is better than putting them in POL.CPP. */
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <cstddef>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <string>
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../bscript/eprog.h"
|
2019-01-03 11:00:46 +01:00
|
|
|
#include "../bscript/impstr.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/clib_endian.h"
|
|
|
|
|
#include "../clib/fdump.h"
|
|
|
|
|
#include "../clib/logfacility.h"
|
|
|
|
|
#include "../clib/rawtypes.h"
|
|
|
|
|
#include "../clib/refptr.h"
|
|
|
|
|
#include "../clib/stlutil.h"
|
|
|
|
|
#include "../plib/systemstate.h"
|
2018-12-21 20:27:05 +01:00
|
|
|
#include "../plib/uconst.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "accounts/account.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "cmbtcfg.h"
|
|
|
|
|
#include "fnsearch.h"
|
|
|
|
|
#include "gameclck.h"
|
|
|
|
|
#include "globals/settings.h"
|
|
|
|
|
#include "globals/uvars.h"
|
2020-02-29 16:23:32 +01:00
|
|
|
#include "guilds.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "mobile/attribute.h"
|
|
|
|
|
#include "mobile/charactr.h"
|
|
|
|
|
#include "multi/customhouses.h"
|
|
|
|
|
#include "multi/multi.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "network/client.h"
|
2019-03-07 23:15:41 +01:00
|
|
|
#include "network/clientio.h"
|
2018-01-01 21:49:30 +01:00
|
|
|
#include "network/packethelper.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "network/packets.h"
|
2018-12-30 21:35:54 +01:00
|
|
|
#include "network/pktboth.h"
|
|
|
|
|
#include "network/pktdef.h"
|
|
|
|
|
#include "network/pktin.h"
|
2018-12-30 21:58:07 +01:00
|
|
|
#include "network/sockio.h"
|
2020-02-29 16:23:32 +01:00
|
|
|
#include "party.h"
|
|
|
|
|
#include "realms/realm.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "scrstore.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "spells.h"
|
|
|
|
|
#include "tooltips.h"
|
|
|
|
|
#include "ufunc.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "uobject.h"
|
|
|
|
|
#include "uoscrobj.h"
|
2018-12-21 20:27:05 +01:00
|
|
|
#include <format/format.h>
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace Module
|
|
|
|
|
{
|
|
|
|
|
void character_race_changer_handler( Network::Client* client, Core::PKTBI_BF* msg );
|
|
|
|
|
}
|
|
|
|
|
namespace Core
|
|
|
|
|
{
|
|
|
|
|
using namespace Network;
|
|
|
|
|
|
|
|
|
|
void handle_unknown_packet( Client* client );
|
|
|
|
|
|
|
|
|
|
void party_cmd_handler( Client* client, PKTBI_BF* msg );
|
|
|
|
|
|
|
|
|
|
void OnGuildButton( Client* client );
|
|
|
|
|
void OnQuestButton( Client* client );
|
|
|
|
|
void OnChatButton( Client* client );
|
|
|
|
|
|
|
|
|
|
void handle_bulletin_boards( Client* client, PKTBI_71* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_mode_set( Client* client, PKTBI_72* msg )
|
|
|
|
|
{
|
|
|
|
|
if ( client->chr->warmode_wait > read_gameclock() )
|
|
|
|
|
{
|
|
|
|
|
send_move( client, client->chr );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
client->chr->warmode_wait = read_gameclock() + settingsManager.combat_config.warmode_delay;
|
2016-02-11 22:54:43 +01:00
|
|
|
}
|
2016-02-12 17:37:27 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
bool msg_warmode = msg->warmode ? true : false;
|
|
|
|
|
|
|
|
|
|
// FIXME: Should reply with 0x77 packet!? (so says various docs!) [TJ]
|
|
|
|
|
transmit( client, msg, sizeof *msg );
|
|
|
|
|
|
|
|
|
|
client->chr->set_warmode( msg_warmode );
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 23:15:41 +01:00
|
|
|
void handle_keep_alive( Network::Client* client, PKTBI_73* msg )
|
|
|
|
|
{
|
|
|
|
|
transmit( client, msg, sizeof *msg );
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void handle_rename_char( Client* client, PKTIN_75* msg )
|
|
|
|
|
{
|
|
|
|
|
Mobile::Character* chr = find_character( cfBEu32( msg->serial ) );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( chr != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
if ( client->chr->can_rename( chr ) )
|
|
|
|
|
{
|
|
|
|
|
msg->name[sizeof msg->name - 1] = '\0';
|
|
|
|
|
// check for legal characters
|
|
|
|
|
for ( char* p = msg->name; *p; p++ )
|
|
|
|
|
{
|
|
|
|
|
// only allow: a-z, A-Z & spaces
|
|
|
|
|
if ( *p != ' ' && !isalpha( *p ) )
|
|
|
|
|
{
|
|
|
|
|
fmt::Writer tmp;
|
|
|
|
|
tmp.Format( "Client#{} (account {}) attempted an invalid rename (packet 0x{:X}):\n{}\n" )
|
|
|
|
|
<< client->instance_
|
2018-07-31 14:30:29 +02:00
|
|
|
<< ( ( client->acct != nullptr ) ? client->acct->name() : "unknown" )
|
2016-02-19 19:26:35 +01:00
|
|
|
<< (int)msg->msgtype << msg->name;
|
|
|
|
|
Clib::fdump( tmp, msg->name, static_cast<int>( strlen( msg->name ) ) );
|
|
|
|
|
POLLOG_INFO << tmp.str();
|
|
|
|
|
*p = '\0';
|
|
|
|
|
send_sysmessage( client, "Invalid name!" );
|
|
|
|
|
return; // dave 12/26 if invalid name, do not apply to chr!
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
chr->setname( msg->name );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
send_sysmessage( client, "I can't rename that." );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
send_sysmessage( client, "I can't find that." );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_msg_B5( Client* client, PKTIN_B5* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
OnChatButton( client );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_char_profile_request( Client* client, PKTBI_B8_IN* msg )
|
|
|
|
|
{
|
|
|
|
|
ref_ptr<Bscript::EScriptProgram> prog =
|
|
|
|
|
find_script( "misc/charprofile", true, Plib::systemstate.config.cache_interactive_scripts );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( prog.get() != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
Mobile::Character* mobile;
|
|
|
|
|
|
|
|
|
|
if ( msg->mode == msg->MODE_REQUEST )
|
|
|
|
|
{
|
|
|
|
|
mobile = system_find_mobile( cfBEu32( msg->profile_request.serial ) );
|
|
|
|
|
if ( mobile == nullptr )
|
|
|
|
|
return;
|
|
|
|
|
client->chr->start_script( prog.get(), false, new Module::ECharacterRefObjImp( mobile ),
|
|
|
|
|
new Bscript::BLong( msg->mode ), new Bscript::BLong( 0 ) );
|
|
|
|
|
}
|
|
|
|
|
else if ( msg->mode == msg->MODE_UPDATE )
|
|
|
|
|
{
|
|
|
|
|
mobile = system_find_mobile( cfBEu32( msg->profile_update.serial ) );
|
|
|
|
|
if ( mobile == nullptr )
|
2016-02-12 17:37:27 +01:00
|
|
|
return;
|
2016-02-19 19:26:35 +01:00
|
|
|
u16* themsg = msg->profile_update.wtext;
|
|
|
|
|
int intextlen = ( cfBEu16( msg->msglen ) - 12 ) / sizeof( msg->profile_update.wtext[0] );
|
|
|
|
|
|
|
|
|
|
if ( intextlen < 0 )
|
|
|
|
|
intextlen = 0;
|
|
|
|
|
if ( intextlen > SPEECH_MAX_LEN )
|
|
|
|
|
intextlen = SPEECH_MAX_LEN;
|
2019-01-03 11:00:46 +01:00
|
|
|
std::string text = Bscript::String::fromUTF16( themsg, intextlen, true );
|
|
|
|
|
client->chr->start_script( prog.get(), false, new Module::ECharacterRefObjImp( mobile ),
|
2019-01-12 17:14:05 +01:00
|
|
|
new Bscript::BLong( msg->mode ), new Bscript::String( text ) );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_msg_BB( Client* client, PKTBI_BB* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_client_version( Client* client, PKTBI_BD* msg )
|
|
|
|
|
{
|
|
|
|
|
u16 len = cfBEu16( msg->msglen ) - 3;
|
|
|
|
|
if ( len < 100 )
|
|
|
|
|
{
|
|
|
|
|
int c = 0;
|
|
|
|
|
char ch;
|
|
|
|
|
std::string ver2 = "";
|
|
|
|
|
while ( c < len )
|
|
|
|
|
{
|
|
|
|
|
ch = msg->version[c];
|
|
|
|
|
if ( ch == 0 )
|
|
|
|
|
break; // seems to be null-terminated
|
|
|
|
|
ver2 += ch;
|
|
|
|
|
++c;
|
|
|
|
|
}
|
|
|
|
|
client->setversion( ver2 );
|
|
|
|
|
|
|
|
|
|
VersionDetailStruct vers_det;
|
|
|
|
|
client->itemizeclientversion( ver2, vers_det );
|
|
|
|
|
client->setversiondetail( vers_det );
|
|
|
|
|
|
|
|
|
|
if ( client->compareVersion( CLIENT_VER_70331 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_70331 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_70300 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_70300 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_70130 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_70130 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_7090 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_7090 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_7000 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_7000 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_60142 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_60142 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_6017 ) ) // Grid-loc support
|
|
|
|
|
client->setClientType( CLIENTTYPE_6017 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_5020 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_5020 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_5000 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_5000 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_4070 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_4070 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_4000 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_4000 );
|
|
|
|
|
|
|
|
|
|
if ( settingsManager.ssopt.core_sends_season )
|
|
|
|
|
send_season_info(
|
|
|
|
|
client ); // Scott 10/11/2007 added for login fixes and handling 1.x clients.
|
|
|
|
|
// Season info needs to check client version to keep from crashing 1.x
|
|
|
|
|
// version not set until shortly after login complete.
|
|
|
|
|
// send_feature_enable(client); //dave commented out 8/21/03, unexpected problems with people
|
|
|
|
|
// sending B9 via script with this too.
|
|
|
|
|
if ( ( client->UOExpansionFlag & AOS ) )
|
|
|
|
|
{
|
|
|
|
|
send_object_cache( client, client->chr );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
POLLOG_INFO << "Suspect string length in PKTBI_BD packet: " << len << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ext_stats_in( Client* client, PKTBI_BF* msg )
|
|
|
|
|
{
|
|
|
|
|
if ( settingsManager.ssopt.core_handled_locks )
|
|
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
const Mobile::Attribute* attrib = nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
switch ( msg->extstatin.stat )
|
|
|
|
|
{
|
|
|
|
|
case PKTBI_BF_1A::STAT_STR:
|
|
|
|
|
attrib = gamestate.pAttrStrength;
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF_1A::STAT_DEX:
|
|
|
|
|
attrib = gamestate.pAttrDexterity;
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF_1A::STAT_INT:
|
|
|
|
|
attrib = gamestate.pAttrIntelligence;
|
|
|
|
|
break;
|
|
|
|
|
default: // sent an illegal stat. Should report to console?
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( attrib == nullptr ) // there's no attribute for this (?)
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
u8 state = msg->extstatin.mode;
|
|
|
|
|
if ( state > 2 ) // FIXME hard-coded value
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
client->chr->attribute( attrib->attrid ).lock( state );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_msg_BF( Client* client, PKTBI_BF* msg )
|
|
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
UObject* obj = nullptr;
|
|
|
|
|
Multi::UMulti* multi = nullptr;
|
|
|
|
|
Multi::UHouse* house = nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
switch ( cfBEu16( msg->subcmd ) )
|
|
|
|
|
{
|
|
|
|
|
case PKTBI_BF::TYPE_CLIENT_LANGUAGE:
|
2019-01-12 11:46:30 +01:00
|
|
|
client->chr->uclang = Clib::strlowerASCII( msg->client_lang );
|
2016-02-19 19:26:35 +01:00
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_REQ_FULL_CUSTOM_HOUSE:
|
|
|
|
|
if ( ( client->UOExpansionFlag & AOS ) == 0 )
|
|
|
|
|
return;
|
|
|
|
|
multi = system_find_multi( cfBEu32( msg->reqfullcustomhouse.house_serial ) );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( multi != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
house = multi->as_house();
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( house != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
if ( client->UOExpansionFlag & AOS )
|
|
|
|
|
{
|
|
|
|
|
send_object_cache( client, (UObject*)( house ) );
|
|
|
|
|
}
|
|
|
|
|
// consider sending working design to certain players, to assist building, or GM help
|
|
|
|
|
CustomHousesSendFull( house, client, Multi::HOUSE_DESIGN_CURRENT );
|
2016-02-12 17:37:27 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_OBJECT_CACHE:
|
|
|
|
|
if ( ( client->UOExpansionFlag & AOS ) == 0 )
|
|
|
|
|
return;
|
|
|
|
|
obj = system_find_object( cfBEu32( msg->objectcache.serial ) );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( obj != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
SendAOSTooltip( client, obj );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_SESPAM:
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_SPELL_SELECT:
|
|
|
|
|
do_cast( client, cfBEu16( msg->spellselect.selected_spell ) );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_CHARACTER_RACE_CHANGER:
|
|
|
|
|
Module::character_race_changer_handler( client, msg );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_PARTY_SYSTEM:
|
|
|
|
|
party_cmd_handler( client, msg );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_EXTENDED_STATS_IN:
|
|
|
|
|
ext_stats_in( client, msg );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_CLOSED_STATUS_GUMP:
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_SCREEN_SIZE:
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_TOGGLE_FLYING:
|
2018-12-22 00:32:47 +01:00
|
|
|
if ( client->chr->race == Plib::RACE_GARGOYLE )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
// FIXME: add checks if its possible to stand with new movemode
|
2018-12-22 00:32:47 +01:00
|
|
|
client->chr->movemode = ( Plib::MOVEMODE )( client->chr->movemode ^ Plib::MOVEMODE_FLY );
|
2016-02-19 19:26:35 +01:00
|
|
|
send_move_mobile_to_nearby_cansee( client->chr );
|
|
|
|
|
send_goxyz( client, client->chr );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_CLIENTTYPE:
|
|
|
|
|
client->UOExpansionFlagClient = ctBEu32( msg->clienttype.clientflag );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_BF::TYPE_POPUP_MENU_REQUEST:
|
|
|
|
|
{
|
|
|
|
|
ref_ptr<Bscript::EScriptProgram> prog =
|
|
|
|
|
find_script( "misc/popupmenu", true, Plib::systemstate.config.cache_interactive_scripts );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( prog.get() == nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
break;
|
|
|
|
|
u32 serial = cfBEu32( msg->serial_request_popup_menu );
|
|
|
|
|
if ( IsCharacter( serial ) )
|
|
|
|
|
{
|
|
|
|
|
Pol::Mobile::Character* chr = system_find_mobile( serial );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( chr == nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
break;
|
|
|
|
|
client->chr->start_script( prog.get(), false, new Pol::Module::ECharacterRefObjImp( chr ) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Pol::Items::Item* item = system_find_item( serial );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( item == nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
break;
|
|
|
|
|
client->chr->start_script( prog.get(), false, item->make_ref() );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case PKTBI_BF::TYPE_POPUP_ENTRY_SELECT:
|
|
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( client->chr->on_popup_menu_selection == nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
POLLOG_INFO.Format( "{}/{} tried to use a popup menu, but none was active.\n" )
|
|
|
|
|
<< client->acct->name() << client->chr->name();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 serial = cfBEu32( msg->popupselect.serial );
|
|
|
|
|
u16 id = cfBEu16( msg->popupselect.entry_tag );
|
|
|
|
|
client->chr->on_popup_menu_selection( client, serial, id );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_unknown_C4( Client* client, PKTOUT_C4* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_update_range_change( Client* client, PKTBI_C8* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 16:23:32 +01:00
|
|
|
void handle_krrios_packet( Client* client, PKTBI_F0* msg )
|
|
|
|
|
{
|
|
|
|
|
auto* me = client->chr;
|
|
|
|
|
switch ( msg->subcmd )
|
|
|
|
|
{
|
|
|
|
|
case PKTBI_F0::QUERY_PARTY:
|
|
|
|
|
{
|
2020-03-04 19:37:37 +01:00
|
|
|
if ( !settingsManager.ssopt.enable_worldmap_packets )
|
|
|
|
|
break;
|
2020-02-29 16:23:32 +01:00
|
|
|
|
|
|
|
|
if ( me->has_party() )
|
|
|
|
|
{
|
|
|
|
|
Party* party = me->party();
|
|
|
|
|
Network::PktHelper::PacketOut<Network::PktOut_F0_Sub01> outMsg;
|
2020-03-18 21:55:51 +01:00
|
|
|
outMsg->offset += 2; // len
|
|
|
|
|
outMsg->Write<u8>( PKTBI_F0::QUERY_PARTY + 1U ); // sub, response is +1
|
2020-03-22 20:13:21 +01:00
|
|
|
for ( auto member : party->get_members() )
|
2020-02-29 16:23:32 +01:00
|
|
|
{
|
2020-03-19 12:14:17 +01:00
|
|
|
if ( member->serial == me->serial )
|
2020-02-29 16:23:32 +01:00
|
|
|
continue;
|
|
|
|
|
|
2020-03-19 12:14:17 +01:00
|
|
|
if ( Core::inrange( me, member ) && me->is_visible_to_me( member ) )
|
2020-02-29 16:23:32 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
outMsg->Write<u32>( member->serial_ext );
|
2020-04-07 22:01:31 +02:00
|
|
|
outMsg->WriteFlipped<u16>( member->x() );
|
|
|
|
|
outMsg->WriteFlipped<u16>( member->y() );
|
|
|
|
|
outMsg->Write<u8>( member->realm()->getUOMapID() );
|
2020-03-19 12:14:17 +01:00
|
|
|
}
|
2020-03-18 21:55:51 +01:00
|
|
|
|
2020-02-29 16:23:32 +01:00
|
|
|
if ( outMsg->offset != 4 ) // only send if there is an update
|
|
|
|
|
{
|
|
|
|
|
outMsg->Write<u32>( 0U ); // end of list marker
|
|
|
|
|
u16 len = outMsg->offset;
|
|
|
|
|
outMsg->offset = 1;
|
|
|
|
|
outMsg->WriteFlipped<u16>( len );
|
|
|
|
|
outMsg.Send( client, len );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case PKTBI_F0::QUERY_GUILD:
|
|
|
|
|
{
|
2020-03-04 19:37:37 +01:00
|
|
|
if ( !settingsManager.ssopt.enable_worldmap_packets )
|
|
|
|
|
break;
|
|
|
|
|
|
2020-02-29 16:23:32 +01:00
|
|
|
Guild* guild = me->guild();
|
|
|
|
|
u8 locations = msg->query_guild.include_locations > 0 ? 1U : 0U;
|
|
|
|
|
if ( guild != nullptr )
|
|
|
|
|
{
|
|
|
|
|
Network::PktHelper::PacketOut<Network::PktOut_F0_Sub02> outMsg;
|
2020-03-18 21:55:51 +01:00
|
|
|
outMsg->offset += 2; // len
|
|
|
|
|
outMsg->Write<u8>( PKTBI_F0::QUERY_GUILD + 1U ); // sub, response is +1
|
2020-02-29 16:23:32 +01:00
|
|
|
outMsg->Write<u8>( locations );
|
2020-03-22 20:13:21 +01:00
|
|
|
for ( auto member : guild->get_members() )
|
2020-02-29 16:23:32 +01:00
|
|
|
{
|
2020-03-22 20:13:21 +01:00
|
|
|
if ( member->serial == me->serial )
|
2020-02-29 16:23:32 +01:00
|
|
|
continue;
|
|
|
|
|
|
2020-03-22 20:13:21 +01:00
|
|
|
if ( locations && Core::inrange( me, member ) && me->is_visible_to_me( member ) )
|
2020-02-29 16:23:32 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
outMsg->Write<u32>( member->serial_ext );
|
|
|
|
|
if ( locations )
|
|
|
|
|
{
|
2020-04-07 22:01:31 +02:00
|
|
|
outMsg->WriteFlipped<u16>( member->x() );
|
|
|
|
|
outMsg->WriteFlipped<u16>( member->y() );
|
|
|
|
|
outMsg->Write<u8>( member->realm()->getUOMapID() );
|
2020-02-29 16:23:32 +01:00
|
|
|
|
|
|
|
|
if ( member->dead() )
|
|
|
|
|
outMsg->Write<u8>( 0U );
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int current = member->vital( networkManager.uoclient_general.hits.id ).current_ones();
|
|
|
|
|
int max = member->vital( networkManager.uoclient_general.hits.id ).maximum_ones();
|
|
|
|
|
u8 ratio = static_cast<u8>( 100 * current / ( max < 1 ? 1 : max ) );
|
|
|
|
|
outMsg->Write<u8>( ratio ); // hits
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( outMsg->offset != 5 ) // only send if there is an update
|
|
|
|
|
{
|
|
|
|
|
outMsg->Write<u32>( 0U ); // end of list marker
|
|
|
|
|
u16 len = outMsg->offset;
|
|
|
|
|
outMsg->offset = 1;
|
|
|
|
|
outMsg->WriteFlipped<u16>( len );
|
|
|
|
|
outMsg.Send( client, len );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-29 11:42:03 +01:00
|
|
|
void handle_open_uo_store( Client* client, PKTIN_FA* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_update_view_public_house_content( Client* client, PKTIN_FB* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void handle_allnames( Client* client, PKTBI_98_IN* msg )
|
|
|
|
|
{
|
|
|
|
|
u32 serial = cfBEu32( msg->serial );
|
|
|
|
|
Mobile::Character* the_mob = find_character( serial );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( the_mob != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
if ( !client->chr->is_visible_to_me( the_mob ) )
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-04-05 21:17:38 +02:00
|
|
|
if ( !client->chr->pos().inRange( the_mob->pos(), 20 ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PktHelper::PacketOut<PktOut_98> msgOut;
|
|
|
|
|
msgOut->WriteFlipped<u16>( 37u ); // static length
|
|
|
|
|
msgOut->Write<u32>( the_mob->serial_ext );
|
|
|
|
|
msgOut->Write( the_mob->name().c_str(), 30, false );
|
|
|
|
|
msgOut.Send( client );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_se_object_list( Client* client, PKTBI_D6_IN* msgin )
|
|
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
UObject* obj = nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
int length = cfBEu16( msgin->msglen ) - 3;
|
|
|
|
|
if ( length < 0 || ( length % 4 ) != 0 )
|
|
|
|
|
return;
|
|
|
|
|
int count = length / 4;
|
|
|
|
|
|
|
|
|
|
for ( int i = 0; i < count; ++i )
|
|
|
|
|
{
|
|
|
|
|
obj = system_find_object( cfBEu32( msgin->serials[i].serial ) );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( obj != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
SendAOSTooltip( client, obj );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_ef_seed( Client* client, PKTIN_EF* msg )
|
|
|
|
|
{
|
|
|
|
|
VersionDetailStruct detail;
|
|
|
|
|
detail.major = cfBEu32( msg->ver_Major );
|
|
|
|
|
detail.minor = cfBEu32( msg->ver_Minor );
|
|
|
|
|
detail.rev = cfBEu32( msg->ver_Revision );
|
|
|
|
|
detail.patch = cfBEu32( msg->ver_Patch );
|
|
|
|
|
client->setversiondetail( detail );
|
|
|
|
|
if ( client->compareVersion( CLIENT_VER_70331 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_70331 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_70300 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_70300 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_70130 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_70130 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_7090 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_7090 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_7000 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_7000 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_60142 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_60142 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_6017 ) ) // Grid-loc support
|
|
|
|
|
client->setClientType( CLIENTTYPE_6017 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_5020 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_5020 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_5000 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_5000 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_4070 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_4070 );
|
|
|
|
|
else if ( client->compareVersion( CLIENT_VER_4000 ) )
|
|
|
|
|
client->setClientType( CLIENTTYPE_4000 );
|
|
|
|
|
|
|
|
|
|
// detail->patch is since 5.0.7 always numeric, so no need to make it complicated
|
|
|
|
|
OSTRINGSTREAM os;
|
|
|
|
|
os << detail.major << "." << detail.minor << "." << detail.rev << "." << detail.patch;
|
|
|
|
|
client->setversion( OSTRINGSTREAM_STR( os ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_e1_clienttype( Client* client, PKTIN_E1* msg )
|
|
|
|
|
{
|
|
|
|
|
switch ( cfBEu32( msg->clienttype ) )
|
|
|
|
|
{
|
|
|
|
|
case PKTIN_E1::CLIENTTYPE_KR:
|
|
|
|
|
client->setClientType( CLIENTTYPE_UOKR );
|
|
|
|
|
break;
|
|
|
|
|
case PKTIN_E1::CLIENTTYPE_SA:
|
|
|
|
|
client->setClientType( CLIENTTYPE_UOSA );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
INFO_PRINT << "Unknown client type send with packet 0xE1 : 0x"
|
|
|
|
|
<< fmt::hexu( static_cast<unsigned long>( cfBEu32( msg->clienttype ) ) ) << "\n";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
/**
|
|
|
|
|
* Handler for a 0xD7 packet
|
|
|
|
|
*/
|
|
|
|
|
void handle_aos_commands( Client* client, PKTBI_D7* msg )
|
|
|
|
|
{
|
|
|
|
|
// nullptr prevention, no need to disturb if client or character is not found
|
|
|
|
|
if ( client == nullptr || client->chr == nullptr )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/// Checks that serial written inside packet matches sending character's serial
|
|
|
|
|
u32 serial = cfBEu32( msg->serial );
|
|
|
|
|
if ( client && client->chr && client->chr->serial != serial )
|
|
|
|
|
{
|
|
|
|
|
INFO_PRINT << "Ignoring spoofed packet 0xD7 from character 0x"
|
|
|
|
|
<< fmt::hexu( client->chr->serial ) << " trying to spoof 0x" << fmt::hexu( serial )
|
|
|
|
|
<< "\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ( cfBEu16( msg->subcmd ) )
|
|
|
|
|
{
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_BACKUP:
|
|
|
|
|
Multi::CustomHousesBackup( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_RESTORE:
|
|
|
|
|
Multi::CustomHousesRestore( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_COMMIT:
|
|
|
|
|
Multi::CustomHousesCommit( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_ERASE:
|
|
|
|
|
Multi::CustomHousesErase( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_ADD:
|
|
|
|
|
Multi::CustomHousesAdd( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_QUIT:
|
|
|
|
|
Multi::CustomHousesQuit( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_ADD_MULTI:
|
|
|
|
|
Multi::CustomHousesAddMulti( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_SYNCH:
|
|
|
|
|
Multi::CustomHousesSynch( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_CLEAR:
|
|
|
|
|
Multi::CustomHousesClear( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_SELECT_FLOOR:
|
|
|
|
|
Multi::CustomHousesSelectFloor( msg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_REVERT:
|
|
|
|
|
Multi::CustomHousesRevert( msg );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_SELECT_ROOF:
|
|
|
|
|
Multi::CustomHousesRoofSelect( msg );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_D7::CUSTOM_HOUSE_DELETE_ROOF:
|
|
|
|
|
Multi::CustomHousesRoofRemove( msg );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_D7::GUILD_BUTTON:
|
|
|
|
|
OnGuildButton( client );
|
|
|
|
|
break;
|
|
|
|
|
case PKTBI_D7::QUEST_BUTTON:
|
|
|
|
|
OnQuestButton( client );
|
|
|
|
|
break;
|
|
|
|
|
// missing combat book abilities
|
|
|
|
|
default:
|
|
|
|
|
handle_unknown_packet( client );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnGuildButton( Client* client )
|
|
|
|
|
{
|
|
|
|
|
ref_ptr<Bscript::EScriptProgram> prog =
|
|
|
|
|
find_script( "misc/guildbutton", true, Plib::systemstate.config.cache_interactive_scripts );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( prog.get() != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
client->chr->start_script( prog.get(), false );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnQuestButton( Client* client )
|
|
|
|
|
{
|
|
|
|
|
ref_ptr<Bscript::EScriptProgram> prog =
|
|
|
|
|
find_script( "misc/questbutton", true, Plib::systemstate.config.cache_interactive_scripts );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( prog.get() != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
client->chr->start_script( prog.get(), false );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnChatButton( Client* client )
|
|
|
|
|
{
|
|
|
|
|
ref_ptr<Bscript::EScriptProgram> prog =
|
|
|
|
|
find_script( "misc/chatbutton", true, Plib::systemstate.config.cache_interactive_scripts );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( prog.get() != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
client->chr->start_script( prog.get(), false );
|
2016-02-11 22:54:43 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2018-12-21 20:27:05 +01:00
|
|
|
} // namespace Core
|
|
|
|
|
} // namespace Pol
|