polserver/pol-core/pol/module/unimod.cpp
Kevin Eady 12d6186d10
Script option enhancements (#118)
* Fix SCRIPTOPT_CAN_ACCESS_OFFLINE_MOBILES

* Add SCRIPTOPT_SURVIVE_ATTACHED_DISCONNECT

* wip beginning work on templatization

* Use PolModule in pol-specific modules

* wip, creating PolModule with getXYZParam

* wip 1, moving getXYZ to UOExecutor

* compilable with PolObjectImp / PolApplicObj

* add type guard

* wip, change signatures

change signatures of script_method, script_method_id, and
custom_script_method

* compilable (windows)

* linux fixes

* namespace fixes

* remove uoexhelp

* formatting

* compilable

- move can_access_offline_mobiles back to uoexec
- add guildscrobj and partyscrobj sources
- move EGuildRefObjImp and EPartyRefObjImp
- wip, implement asUOExec
- formatting uoexec.cpp,.h

* finish uoexec() helper

* some cleanup
2020-02-08 09:21:35 +01:00

295 lines
8.8 KiB
C++

/** @file
*
* @par History
* - 2006/10/07 Shinigami: GCC 3.4.x fix - added "template<>" to TmplExecutorModule
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
*/
#include "unimod.h"
#include <iostream>
#include <string.h>
#include "../../bscript/berror.h"
#include "../../bscript/bobject.h"
#include "../../bscript/impstr.h"
#include "../../clib/clib_endian.h"
#include "../../clib/logfacility.h"
#include "../accounts/account.h"
#include "../item/item.h"
#include "../mobile/charactr.h"
#include "../network/cgdata.h"
#include "../network/client.h"
#include "../network/packethelper.h"
#include "../network/packets.h"
#include "../network/pktboth.h"
#include "../network/pktdef.h"
#include "../ufunc.h"
#include "../uoexec.h"
#include "uomod.h"
#include <module_defs/unicode.h>
namespace Pol
{
namespace Core
{
using namespace Network;
void send_unicode_prompt( Client* client, u32 serial )
{
PktHelper::PacketOut<PktOut_C2> msg;
msg->WriteFlipped<u16>( Core::PKTBI_C2::SERVER_MSGLEN );
msg->Write<u32>( serial ); // serial
msg->Write<u32>( serial ); // msg_id Server-"decided" message ID. o_O
msg->offset += 10; // 10x u8 unk
msg.Send( client );
}
void handle_unicode_prompt( Client* client, Core::PKTBI_C2* msg )
{
// TODO do we really need two of them, this can also be done differently
Module::UnicodeExecutorModule* uniemod = client->gd->prompt_uniemod;
Module::UOExecutorModule* uoemod = client->gd->prompt_uoemod;
if ( uoemod == nullptr && uniemod == nullptr )
return; // log it?
int textlen = ( ( cfBEu16( msg->msglen ) - offsetof( Core::PKTBI_C2, wtext ) ) /
sizeof( msg->wtext[0] ) ); // note NO terminator!
if ( textlen < 0 )
textlen = 0;
if ( textlen > SPEECH_MAX_LEN )
{
textlen = SPEECH_MAX_LEN; // ENHANCE: May want to log this
msg->wtext[textlen] = 0x0000;
}
// client version of the packet should always send this as a 1??
/*if ( cfBEu16( msg->unk ) != 0x01 )
{
// ENHANCE: May want to log this, too?
ok = false;
valstack = new BObject( new BError( "Malformed return-packet from client" ) );
}*/
char lang[4];
memcpy( lang, msg->lang, 4 );
// String::fromUTF16 performs all the error checks
// "Invalid unicode" will be returned if completly broken, but do we really need to take care?
if ( uniemod != nullptr && uniemod->prompt_chr != nullptr )
{
std::unique_ptr<Bscript::BStruct> retval( new Bscript::BStruct() );
retval->addMember( "lang", new Bscript::String( lang ) );
retval->addMember( "text",
new Bscript::String( Bscript::String::fromUTF16( msg->wtext, textlen ) ) );
uniemod->exec.ValueStack.back().set( new Bscript::BObject( retval.release() ) );
uniemod->uoexec().revive();
}
else if ( uoemod != nullptr && uoemod->prompt_chr != nullptr )
{
// called from uo module, directly return string
uoemod->exec.ValueStack.back().set( new Bscript::BObject(
new Bscript::String( Bscript::String::fromUTF16( msg->wtext, textlen ) ) ) );
uoemod->uoexec().revive();
}
if ( uniemod != nullptr )
uniemod->prompt_chr = nullptr;
if ( uoemod != nullptr )
uoemod->prompt_chr = nullptr;
client->gd->prompt_uniemod = nullptr;
client->gd->prompt_uoemod = nullptr;
}
//////////////////////////////////////////////////////////////////////////
} // namespace Core
namespace Module
{
using namespace Bscript;
UnicodeExecutorModule::UnicodeExecutorModule( Core::UOExecutor& exec )
: TmplExecutorModule<UnicodeExecutorModule, Core::PolModule>( exec ), prompt_chr( nullptr )
{
}
UnicodeExecutorModule::~UnicodeExecutorModule()
{
if ( prompt_chr != nullptr )
{
prompt_chr->client->gd->prompt_uniemod = nullptr;
prompt_chr = nullptr;
}
}
BObjectImp* UnicodeExecutorModule::mf_BroadcastUC()
{
const String* text;
const String* lang;
unsigned short font;
unsigned short color;
unsigned short requiredCmdLevel;
if ( getUnicodeStringParam( 0, text ) && getStringParam( 1, lang ) &&
getParam( 2, font ) && // todo: getFontParam
getParam( 3, color ) && // todo: getColorParam
getParam( 4, requiredCmdLevel ) ) // todo: getRequiredCmdLevelParam
{
if ( text->length() > SPEECH_MAX_LEN )
return new BError( "Text exceeds maximum size." );
if ( lang->length() != 3 )
return new BError( "langcode must be a 3-character code." );
Core::broadcast_unicode( text->value(), Clib::strupperASCII( lang->value() ), font, color,
requiredCmdLevel );
return new BLong( 1 );
}
else
{
return new BError( "A parameter was invalid" );
}
}
BObjectImp* UnicodeExecutorModule::mf_PrintTextAboveUC()
{
Core::UObject* obj;
const String* text;
const String* lang;
unsigned short font;
unsigned short color;
int journal_print;
if ( getUObjectParam( 0, obj ) && getUnicodeStringParam( 1, text ) && getStringParam( 2, lang ) &&
getParam( 3, font ) && getParam( 4, color ) && getParam( 5, journal_print ) )
{
if ( text->length() > SPEECH_MAX_LEN )
return new BError( "Text exceeds maximum size." );
if ( lang->length() != 3 )
return new BError( "langcode must be a 3-character code." );
return new BLong( say_above_unicode( obj, text->value(), Clib::strupperASCII( lang->value() ),
font, color, journal_print ) );
}
else
{
return new BError( "A parameter was invalid" );
}
}
BObjectImp* UnicodeExecutorModule::mf_PrintTextAbovePrivateUC()
{
Mobile::Character* chr;
Core::UObject* obj;
const String* text;
const String* lang;
unsigned short font;
unsigned short color;
if ( getUObjectParam( 0, obj ) && getUnicodeStringParam( 1, text ) && getStringParam( 2, lang ) &&
getCharacterParam( 3, chr ) && getParam( 4, font ) && getParam( 5, color ) )
{
if ( text->length() > SPEECH_MAX_LEN )
return new BError( "Text exceeds maximum size." );
if ( lang->length() != 3 )
return new BError( "langcode must be a 3-character code." );
return new BLong( private_say_above_unicode(
chr, obj, text->value(), Clib::strupperASCII( lang->value() ), font, color ) );
}
else
{
return new BError( "A parameter was invalid" );
}
}
BObjectImp* UnicodeExecutorModule::mf_RequestInputUC()
{
Mobile::Character* chr;
Items::Item* item;
const String* prompt;
const String* lang;
if ( getCharacterParam( 0, chr ) && getItemParam( 1, item ) &&
getUnicodeStringParam( 2, prompt ) && getStringParam( 3, lang ) )
{
if ( !chr->has_active_client() )
{
return new BError( "No client attached" );
}
if ( chr->has_active_prompt() )
{
return new BError( "Another script has an active prompt" );
}
if ( prompt->length() > SPEECH_MAX_LEN )
return new BError( "Prompt exceeds maximum size." );
if ( lang->length() != 3 )
return new BError( "langcode must be a 3-character code." );
if ( !uoexec().suspend() )
{
DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
<< "\tCall to function Unicode::RequestInputUC():\n"
<< "\tThe execution of this script can't be blocked!\n";
return new Bscript::BError( "Script can't be blocked" );
}
Core::send_sysmessage_unicode( chr->client, prompt->value(),
Clib::strupperASCII( lang->value() ) );
chr->client->gd->prompt_uniemod = this;
prompt_chr = chr;
Core::send_unicode_prompt( chr->client, ctBEu32( item->serial ) );
return new BLong( 0 );
}
else
{
return new BError( "A parameter was invalid" );
}
}
BObjectImp* UnicodeExecutorModule::mf_SendSysMessageUC()
{
Mobile::Character* chr;
const String* text;
const String* lang;
unsigned short font;
unsigned short color;
if ( getCharacterParam( 0, chr ) && getUnicodeStringParam( 1, text ) &&
getStringParam( 2, lang ) && getParam( 3, font ) && getParam( 4, color ) )
{
if ( chr->has_active_client() )
{
if ( text->length() > SPEECH_MAX_LEN )
return new BError( "Text exceeds maximum size." );
if ( lang->length() != 3 )
return new BError( "langcode must be a 3-character code." );
Core::send_sysmessage_unicode( chr->client, text->value(),
Clib::strupperASCII( lang->value() ), font, color );
return new BLong( 1 );
}
else
{
return new BError( "Mobile has no active client" );
}
}
else
{
return new BError( "Invalid parameter type" );
}
}
BObjectImp* UnicodeExecutorModule::mf_SendTextEntryGumpUC()
{
// SendTextEntryGumpUC(who, uc_text1, cancel := TE_CANCEL_ENABLE,
// style := TE_STYLE_NORMAL, maximum := 40, uc_text2 := {} );
return new BError( "Function not implimented" );
}
size_t UnicodeExecutorModule::sizeEstimate() const
{
return sizeof( *this );
}
} // namespace Module
} // namespace Pol