2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
* - 2009/07/23 MuadDib: updates for new Enum::Packet Out ID
|
|
|
|
|
* - 2009/08/01 MuadDib: Rewrote where needed to do away with TEXTDEF struct useage. Pointless.
|
|
|
|
|
* - 2009/08/25 Shinigami: STLport-5.2.1 fix: buffer not used
|
|
|
|
|
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
|
|
|
|
|
* - 2009/10/14 Turley: new priv canbeheardasghost
|
|
|
|
|
* - 2009/10/14 Turley: Added char.deaf() methods & char.deafened member
|
|
|
|
|
*/
|
2015-01-16 19:44:07 +01:00
|
|
|
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <cctype>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../bscript/bobject.h"
|
|
|
|
|
#include "../bscript/impstr.h"
|
|
|
|
|
#include "../clib/clib_endian.h"
|
|
|
|
|
#include "../clib/logfacility.h"
|
|
|
|
|
#include "../clib/random.h"
|
|
|
|
|
#include "../clib/rawtypes.h"
|
|
|
|
|
#include "../plib/systemstate.h"
|
|
|
|
|
#include "globals/settings.h"
|
|
|
|
|
#include "globals/uvars.h"
|
|
|
|
|
#include "guilds.h"
|
2015-01-16 19:44:07 +01:00
|
|
|
#include "listenpt.h"
|
|
|
|
|
#include "mkscrobj.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "mobile/charactr.h"
|
|
|
|
|
#include "mobile/npc.h"
|
|
|
|
|
#include "network/client.h"
|
|
|
|
|
#include "network/packethelper.h"
|
|
|
|
|
#include "network/packets.h"
|
2018-12-30 21:35:54 +01:00
|
|
|
#include "network/pktdef.h"
|
|
|
|
|
#include "network/pktin.h"
|
2015-01-16 19:44:07 +01:00
|
|
|
#include "syshook.h"
|
|
|
|
|
#include "textcmd.h"
|
|
|
|
|
#include "tildecmd.h"
|
2018-12-31 20:07:22 +01:00
|
|
|
#include "ufunc.h"
|
2015-01-16 19:44:07 +01:00
|
|
|
#include "ufuncstd.h"
|
|
|
|
|
#include "uworld.h"
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace Core
|
|
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
void handle_processed_speech( Network::Client* client, const std::string& text, u8 type, u16 color,
|
|
|
|
|
u16 font )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
if ( text.empty() )
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
|
2019-01-12 17:14:05 +01:00
|
|
|
std::string s_text( text );
|
|
|
|
|
Clib::sanitizeUnicodeWithIso( &s_text ); // use original text for other clients
|
2016-02-19 19:26:35 +01:00
|
|
|
Mobile::Character* chr = client->chr;
|
|
|
|
|
|
|
|
|
|
// validate text color
|
|
|
|
|
u16 textcol = cfBEu16( color );
|
|
|
|
|
if ( textcol < 2 || textcol > 1001 )
|
|
|
|
|
{
|
|
|
|
|
textcol = 1001;
|
|
|
|
|
}
|
|
|
|
|
chr->last_textcolor( textcol );
|
|
|
|
|
|
2019-01-12 17:14:05 +01:00
|
|
|
if ( s_text[0] == '.' || s_text[0] == '=' )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2019-01-12 17:14:05 +01:00
|
|
|
if ( !process_command( client, s_text ) )
|
2019-01-02 23:35:38 +01:00
|
|
|
send_sysmessage( client, std::string( "Unknown command: " ) + text );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2019-01-12 17:14:05 +01:00
|
|
|
if ( s_text[0] == '~' )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2019-01-12 17:14:05 +01:00
|
|
|
process_tildecommand( client, s_text );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( chr->squelched() )
|
|
|
|
|
return;
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( chr->hidden() )
|
|
|
|
|
chr->unhide();
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Plib::systemstate.config.show_speech_colors )
|
|
|
|
|
{
|
|
|
|
|
INFO_PRINT << chr->name() << " speaking w/ color 0x" << fmt::hexu( cfBEu16( color ) ) << "\n";
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 23:35:38 +01:00
|
|
|
u16 textlen = static_cast<u16>( text.size() + 1 );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( textlen > SPEECH_MAX_LEN + 1 )
|
|
|
|
|
textlen = SPEECH_MAX_LEN + 1;
|
|
|
|
|
|
|
|
|
|
Network::PktHelper::PacketOut<Network::PktOut_1C> talkmsg;
|
|
|
|
|
talkmsg->offset += 2;
|
|
|
|
|
talkmsg->Write<u32>( chr->serial_ext );
|
|
|
|
|
talkmsg->WriteFlipped<u16>( chr->graphic );
|
|
|
|
|
talkmsg->Write<u8>( type ); // FIXME authorize
|
|
|
|
|
talkmsg->WriteFlipped<u16>( textcol );
|
|
|
|
|
talkmsg->WriteFlipped<u16>( font );
|
|
|
|
|
talkmsg->Write( chr->name().c_str(), 30 );
|
2019-01-02 23:35:38 +01:00
|
|
|
talkmsg->Write( text.c_str(), textlen );
|
2016-02-19 19:26:35 +01:00
|
|
|
u16 len = talkmsg->offset;
|
|
|
|
|
talkmsg->offset = 1;
|
|
|
|
|
talkmsg->WriteFlipped<u16>( len );
|
|
|
|
|
talkmsg.Send( client, len );
|
|
|
|
|
|
|
|
|
|
Network::PktHelper::PacketOut<Network::PktOut_1C> ghostmsg;
|
|
|
|
|
if ( chr->dead() && !chr->can_be_heard_as_ghost() )
|
|
|
|
|
{
|
|
|
|
|
memcpy( &ghostmsg->buffer, &talkmsg->buffer, sizeof ghostmsg->buffer );
|
|
|
|
|
ghostmsg->offset = 44;
|
|
|
|
|
char* t = &ghostmsg->buffer[ghostmsg->offset];
|
|
|
|
|
while ( ghostmsg->offset < len )
|
|
|
|
|
{
|
|
|
|
|
if ( !isspace( *t ) )
|
2015-01-16 19:44:07 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Clib::random_int( 3 ) == 0 )
|
|
|
|
|
*t = 'o';
|
|
|
|
|
else
|
|
|
|
|
*t = 'O';
|
2015-01-16 19:44:07 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
++t;
|
|
|
|
|
ghostmsg->offset++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// send to those nearby
|
|
|
|
|
u16 range;
|
2018-12-22 00:32:47 +01:00
|
|
|
if ( type == Plib::TEXTTYPE_WHISPER )
|
2016-02-19 19:26:35 +01:00
|
|
|
range = Core::settingsManager.ssopt.whisper_range;
|
2018-12-22 00:32:47 +01:00
|
|
|
else if ( type == Plib::TEXTTYPE_YELL )
|
2016-02-19 19:26:35 +01:00
|
|
|
range = Core::settingsManager.ssopt.yell_range;
|
|
|
|
|
else
|
|
|
|
|
range = Core::settingsManager.ssopt.speech_range;
|
|
|
|
|
Core::WorldIterator<Core::OnlinePlayerFilter>::InRange(
|
2020-04-13 20:12:44 +02:00
|
|
|
chr->pos(), range, [&]( Mobile::Character* other_chr ) {
|
2015-01-16 19:44:07 +01:00
|
|
|
Network::Client* client2 = other_chr->client;
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( client == client2 )
|
|
|
|
|
return;
|
|
|
|
|
if ( !other_chr->is_visible_to_me( chr ) )
|
|
|
|
|
return;
|
|
|
|
|
if ( other_chr->deafened() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( !chr->dead() || other_chr->dead() || other_chr->can_hearghosts() ||
|
2015-01-16 19:44:07 +01:00
|
|
|
chr->can_be_heard_as_ghost() )
|
|
|
|
|
{
|
|
|
|
|
talkmsg.Send( client2, len );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ghostmsg.Send( client2, len );
|
|
|
|
|
}
|
|
|
|
|
} );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !chr->dead() )
|
|
|
|
|
{
|
|
|
|
|
Core::WorldIterator<Core::NPCFilter>::InRange(
|
2020-04-13 20:12:44 +02:00
|
|
|
chr->pos(), range, [&]( Mobile::Character* otherchr ) {
|
2015-01-16 19:44:07 +01:00
|
|
|
Mobile::NPC* npc = static_cast<Mobile::NPC*>( otherchr );
|
2019-01-12 17:14:05 +01:00
|
|
|
npc->on_pc_spoke( chr, s_text, type );
|
2015-01-16 19:44:07 +01:00
|
|
|
} );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Core::WorldIterator<Core::NPCFilter>::InRange(
|
2020-04-13 20:12:44 +02:00
|
|
|
chr->pos(), range, [&]( Mobile::Character* otherchr ) {
|
2015-01-16 19:44:07 +01:00
|
|
|
Mobile::NPC* npc = static_cast<Mobile::NPC*>( otherchr );
|
2019-01-12 17:14:05 +01:00
|
|
|
npc->on_ghost_pc_spoke( chr, s_text, type );
|
2015-01-16 19:44:07 +01:00
|
|
|
} );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2019-01-12 17:14:05 +01:00
|
|
|
sayto_listening_points( client->chr, s_text, type );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-01-16 19:44:07 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void SpeechHandler( Network::Client* client, PKTIN_03* mymsg )
|
|
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
int intextlen = cfBEu16( mymsg->msglen ) - offsetof( PKTIN_03, text ) - 1;
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2019-09-06 21:02:14 +02:00
|
|
|
// Preprocess the text into a sanity-checked, printable form in text
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( intextlen < 0 )
|
|
|
|
|
intextlen = 0;
|
|
|
|
|
if ( intextlen > SPEECH_MAX_LEN )
|
|
|
|
|
intextlen = SPEECH_MAX_LEN; // ENHANCE: May want to log this
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2019-01-02 23:35:38 +01:00
|
|
|
std::string text;
|
2019-09-06 21:02:14 +02:00
|
|
|
text.reserve( intextlen );
|
2019-01-02 23:35:38 +01:00
|
|
|
for ( int i = 0; i < intextlen; i++ )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
char ch = mymsg->text[i];
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( ch == 0 )
|
|
|
|
|
break;
|
|
|
|
|
if ( isprint( ch ) )
|
2019-01-02 23:35:38 +01:00
|
|
|
text += ch;
|
2016-02-19 19:26:35 +01:00
|
|
|
// ENHANCE: else report client data error? Just log?
|
|
|
|
|
}
|
2019-01-02 23:35:38 +01:00
|
|
|
handle_processed_speech( client, text, mymsg->type, mymsg->color, mymsg->font );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-02 23:35:38 +01:00
|
|
|
void SendUnicodeSpeech( Network::Client* client, PKTIN_AD* msgin, const std::string& text,
|
|
|
|
|
Bscript::ObjArray* speechtokens )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
if ( text.empty() )
|
|
|
|
|
return;
|
2016-02-19 19:26:35 +01:00
|
|
|
// validate text color
|
|
|
|
|
u16 textcol = cfBEu16( msgin->color );
|
|
|
|
|
if ( textcol < 2 || textcol > 1001 )
|
|
|
|
|
{
|
|
|
|
|
// 3/8/2009 MuadDib Changed to default color instead of complain.
|
|
|
|
|
textcol = 1001;
|
|
|
|
|
}
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Mobile::Character* chr = client->chr;
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
chr->last_textcolor( textcol );
|
|
|
|
|
|
2019-01-02 23:35:38 +01:00
|
|
|
if ( text[0] == '.' || text[0] == '=' )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2019-01-16 21:24:41 +01:00
|
|
|
std::string lang( msgin->lang );
|
|
|
|
|
if ( !process_command( client, text, lang ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2020-01-03 19:25:46 +01:00
|
|
|
std::string tmp( "Unknown command: " + text );
|
2019-01-16 21:24:41 +01:00
|
|
|
send_sysmessage_unicode( client, tmp, lang );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 23:35:38 +01:00
|
|
|
if ( text[0] == '~' )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
process_tildecommand( client, text );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( chr->squelched() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( chr->hidden() )
|
|
|
|
|
chr->unhide();
|
|
|
|
|
|
|
|
|
|
if ( Plib::systemstate.config.show_speech_colors )
|
|
|
|
|
{
|
|
|
|
|
INFO_PRINT << chr->name() << " speaking w/ color 0x" << fmt::hexu( cfBEu16( msgin->color ) )
|
|
|
|
|
<< "\n";
|
|
|
|
|
}
|
2015-01-16 19:44:07 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Network::PktHelper::PacketOut<Network::PktOut_AE> ghostmsg;
|
|
|
|
|
Network::PktHelper::PacketOut<Network::PktOut_AE> talkmsg;
|
|
|
|
|
talkmsg->offset += 2;
|
|
|
|
|
talkmsg->Write<u32>( chr->serial_ext );
|
|
|
|
|
talkmsg->WriteFlipped<u16>( chr->graphic );
|
|
|
|
|
talkmsg->Write<u8>( msgin->type ); // FIXME authorize
|
|
|
|
|
talkmsg->WriteFlipped<u16>( textcol );
|
|
|
|
|
talkmsg->WriteFlipped<u16>( msgin->font );
|
|
|
|
|
talkmsg->Write( msgin->lang, 4 );
|
|
|
|
|
talkmsg->Write( chr->name().c_str(), 30 );
|
2019-01-02 23:35:38 +01:00
|
|
|
|
2019-01-12 17:14:05 +01:00
|
|
|
std::vector<u16> utf16 = Bscript::String::toUTF16( text );
|
2019-01-02 23:35:38 +01:00
|
|
|
if ( utf16.size() > SPEECH_MAX_LEN )
|
|
|
|
|
utf16.resize( SPEECH_MAX_LEN );
|
|
|
|
|
talkmsg->WriteFlipped( utf16, true );
|
2016-02-19 19:26:35 +01:00
|
|
|
u16 len = talkmsg->offset;
|
|
|
|
|
talkmsg->offset = 1;
|
|
|
|
|
talkmsg->WriteFlipped<u16>( len );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( msgin->type == 0x0d )
|
|
|
|
|
{
|
|
|
|
|
auto thisguild = chr->guild();
|
|
|
|
|
if ( settingsManager.ssopt.core_sends_guildmsgs && thisguild != nullptr )
|
|
|
|
|
{
|
|
|
|
|
for ( unsigned cli = 0; cli < networkManager.clients.size(); cli++ )
|
2015-01-16 19:44:07 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
Network::Client* client2 = networkManager.clients[cli];
|
|
|
|
|
if ( !client2->ready )
|
|
|
|
|
continue;
|
|
|
|
|
if ( thisguild->guildid() == client2->chr->guildid() )
|
|
|
|
|
talkmsg.Send( client2, len );
|
2015-01-16 19:44:07 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ( msgin->type == 0x0e )
|
|
|
|
|
{
|
|
|
|
|
auto thisguild = chr->guild();
|
|
|
|
|
if ( settingsManager.ssopt.core_sends_guildmsgs && thisguild != nullptr )
|
|
|
|
|
{
|
|
|
|
|
for ( unsigned cli = 0; cli < networkManager.clients.size(); cli++ )
|
|
|
|
|
{
|
|
|
|
|
Network::Client* client2 = networkManager.clients[cli];
|
|
|
|
|
if ( !client2->ready )
|
|
|
|
|
continue;
|
|
|
|
|
auto otherguild = client2->chr->guild();
|
|
|
|
|
if ( otherguild != nullptr )
|
2015-05-16 10:30:34 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( thisguild->guildid() == otherguild->guildid() ||
|
|
|
|
|
( thisguild->hasAlly( otherguild ) ) )
|
|
|
|
|
talkmsg.Send( client2, len );
|
2015-05-16 10:30:34 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
talkmsg.Send( client, len ); // self
|
|
|
|
|
if ( chr->dead() && !chr->can_be_heard_as_ghost() )
|
|
|
|
|
{
|
|
|
|
|
memcpy( &ghostmsg->buffer, &talkmsg->buffer, sizeof ghostmsg->buffer );
|
|
|
|
|
|
|
|
|
|
ghostmsg->offset = 48;
|
|
|
|
|
u16* t = ( (u16*)&ghostmsg->buffer[ghostmsg->offset] );
|
|
|
|
|
while ( ghostmsg->offset < len - 2 ) // dont convert nullterm
|
|
|
|
|
{
|
|
|
|
|
wchar_t wch = ( *t );
|
|
|
|
|
if ( !iswspace( wch ) )
|
2015-05-16 10:30:34 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Clib::random_int( 3 ) == 0 )
|
|
|
|
|
*t = ctBEu16( L'o' );
|
|
|
|
|
else
|
|
|
|
|
*t = ctBEu16( L'O' );
|
2015-05-16 10:30:34 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
++t;
|
|
|
|
|
ghostmsg->offset += 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// send to those nearby
|
|
|
|
|
u16 range;
|
2018-12-22 00:32:47 +01:00
|
|
|
if ( msgin->type == Plib::TEXTTYPE_WHISPER )
|
2016-02-19 19:26:35 +01:00
|
|
|
range = Core::settingsManager.ssopt.whisper_range;
|
2018-12-22 00:32:47 +01:00
|
|
|
else if ( msgin->type == Plib::TEXTTYPE_YELL )
|
2016-02-19 19:26:35 +01:00
|
|
|
range = Core::settingsManager.ssopt.yell_range;
|
|
|
|
|
else
|
|
|
|
|
range = Core::settingsManager.ssopt.speech_range;
|
|
|
|
|
Core::WorldIterator<Core::OnlinePlayerFilter>::InRange(
|
2020-04-13 20:12:44 +02:00
|
|
|
chr->pos(), range, [&]( Mobile::Character* otherchr ) {
|
2015-01-16 19:44:07 +01:00
|
|
|
Network::Client* client2 = otherchr->client;
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( client == client2 )
|
|
|
|
|
return;
|
|
|
|
|
if ( !otherchr->is_visible_to_me( chr ) )
|
|
|
|
|
return;
|
|
|
|
|
if ( otherchr->deafened() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( !chr->dead() || otherchr->dead() || otherchr->can_hearghosts() ||
|
|
|
|
|
chr->can_be_heard_as_ghost() )
|
2015-01-16 19:44:07 +01:00
|
|
|
{
|
|
|
|
|
talkmsg.Send( client2, len );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ghostmsg.Send( client2, len );
|
|
|
|
|
}
|
|
|
|
|
} );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !chr->dead() )
|
|
|
|
|
{
|
|
|
|
|
Core::WorldIterator<Core::NPCFilter>::InRange(
|
2020-04-13 20:12:44 +02:00
|
|
|
chr->pos(), range, [&]( Mobile::Character* otherchr ) {
|
2015-01-16 19:44:07 +01:00
|
|
|
Mobile::NPC* npc = static_cast<Mobile::NPC*>( otherchr );
|
2019-01-02 23:35:38 +01:00
|
|
|
npc->on_pc_spoke( chr, text, msgin->type, msgin->lang, speechtokens );
|
2015-01-16 19:44:07 +01:00
|
|
|
} );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Core::WorldIterator<Core::NPCFilter>::InRange(
|
2020-04-13 20:12:44 +02:00
|
|
|
chr->pos(), range, [&]( Mobile::Character* otherchr ) {
|
2015-01-16 19:44:07 +01:00
|
|
|
Mobile::NPC* npc = static_cast<Mobile::NPC*>( otherchr );
|
2019-01-02 23:35:38 +01:00
|
|
|
npc->on_ghost_pc_spoke( chr, text, msgin->type, msgin->lang, speechtokens );
|
2015-01-16 19:44:07 +01:00
|
|
|
} );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2019-01-02 23:35:38 +01:00
|
|
|
sayto_listening_points( client->chr, text, msgin->type, msgin->lang, speechtokens );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
u16 Get12BitNumber( u8* thearray, u16 theindex )
|
|
|
|
|
{
|
|
|
|
|
u16 theresult = 0;
|
|
|
|
|
int thenibble = theindex * 3;
|
|
|
|
|
int thebyte = thenibble / 2;
|
|
|
|
|
if ( thenibble % 2 )
|
|
|
|
|
theresult = cfBEu16( *( (u16*)( thearray + thebyte ) ) ) & 0x0FFF;
|
|
|
|
|
else
|
|
|
|
|
theresult = cfBEu16( *( (u16*)( thearray + thebyte ) ) ) >> 4;
|
|
|
|
|
return theresult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnicodeSpeechHandler( Network::Client* client, PKTIN_AD* msgin )
|
|
|
|
|
{
|
|
|
|
|
u16 numtokens = 0;
|
|
|
|
|
std::unique_ptr<Bscript::ObjArray> speechtokens( nullptr );
|
2019-01-02 23:35:38 +01:00
|
|
|
std::string text;
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( msgin->type & 0xc0 )
|
|
|
|
|
{
|
|
|
|
|
numtokens = Get12BitNumber( (u8*)( msgin->wtext ), 0 );
|
2019-01-02 23:35:38 +01:00
|
|
|
int wtextoffset = ( ( ( ( numtokens + 1 ) * 3 ) / 2 ) + ( ( numtokens + 1 ) % 2 ) );
|
|
|
|
|
int bytemsglen = cfBEu16( msgin->msglen ) - wtextoffset - offsetof( Core::PKTIN_AD, wtext ) - 1;
|
|
|
|
|
if ( bytemsglen < 0 )
|
|
|
|
|
bytemsglen = 0;
|
|
|
|
|
text = Bscript::String::fromUTF8( reinterpret_cast<const char*>( msgin->wtext ) + wtextoffset,
|
|
|
|
|
bytemsglen );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
int intextlen = ( cfBEu16( msgin->msglen ) - offsetof( Core::PKTIN_AD, wtext ) ) /
|
|
|
|
|
sizeof( msgin->wtext[0] ) -
|
|
|
|
|
1;
|
|
|
|
|
if ( intextlen < 0 )
|
|
|
|
|
intextlen = 0;
|
|
|
|
|
text = Bscript::String::fromUTF16( msgin->wtext, intextlen, true );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2019-01-02 23:35:38 +01:00
|
|
|
// SPEECH_MAX_LEN needs to be checked later
|
2019-01-12 17:14:05 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( msgin->type & 0xc0 )
|
|
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
speechtokens.reset( new Bscript::ObjArray() );
|
2016-02-19 19:26:35 +01:00
|
|
|
for ( u16 j = 0; j < numtokens; j++ )
|
|
|
|
|
{
|
2019-01-02 23:35:38 +01:00
|
|
|
speechtokens->addElement(
|
|
|
|
|
new Bscript::BLong( Get12BitNumber( (u8*)( msgin->wtext ), j + 1 ) ) );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2018-10-14 13:13:16 +02:00
|
|
|
if ( gamestate.system_hooks.speechmul_hook )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2019-01-12 17:14:05 +01:00
|
|
|
gamestate.system_hooks.speechmul_hook->call( make_mobileref( client->chr ),
|
|
|
|
|
new Bscript::ObjArray( *speechtokens.get() ),
|
|
|
|
|
new Bscript::String( text ) );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
msgin->type &= ( ~0xC0 ); // Client won't accept C0 text type messages, so must set to 0
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 23:35:38 +01:00
|
|
|
SendUnicodeSpeech( client, msgin, text, speechtokens.release() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2018-12-23 10:24:46 +01:00
|
|
|
} // namespace Core
|
|
|
|
|
} // namespace Pol
|