polserver/pol-core/pol/uoscrobj.cpp
turleypol 6a2bd7c705 Merge remote-tracking branch 'origin/master' into vector_classes
* origin/master: (93 commits)
  Add support for dictionary creation (#277)
  Add do-while statement (#276)
  Add foreach loops (#275)
  New compiler: array initialization (#274)
  Disambiguator: figure out if label is a case statement dispatch selector, or should apply to a statement within the case dispatch group's block. (#273)
  New compiler: Add support for case statements (#272)
  Change "logical" to "bitwise". (#258)
  Fix divide-by-zero errors, and mask FormatError if it were thrown in a destructor. (#271)
  Add break and continue statements. (#270)
  New compiler: assignment to local and global variables. (#269)
  Add support for while loops (#268)
  Optimize if statements, and emit module functions in legacy order (#267)
  Optimizations: binary operators (#266)
  Add binary operators (#265)
  Add support for const declarations (#264)
  Handle default parameter values, pass-by-name, and return statements in functions. (#263)
  Add limited support for user functions (#262)
  New compiler: add return and exit statements (#261)
  Add support for if-then-else statements (#259)
  OG compiler: set module to Mod_Basic when a token is an identifier (#257)
  ...
2020-09-06 20:14:26 +02:00

4914 lines
137 KiB
C++

/** @file
*
* @par History
* - 2005/01/24 Shinigami: added ObjMember character.spyonclient2 to get data from packet 0xd9 (Spy
* on Client 2)
* - 2005/03/09 Shinigami: Added Prop Character::Delay_Mod [ms] for WeaponDelay
* - 2005/04/02 Shinigami: UBoat::script_method_id & UBoat::script_method - added optional realm
* param
* - 2005/04/04 Shinigami: Added Prop Character::CreatedAt [PolClock]
* - 2005/08/29 Shinigami: get-/setspyonclient2 renamed to get-/setclientinfo
* - 2005/11/26 Shinigami: changed "strcmp" into "stricmp" to suppress Script Errors
* - 2005/12/09 MuadDib: Added uclang member for storing UC language from client.
* - 2005/12/09 MuadDib: Fixed ~ItemGivenEvent not returning items correctly if the script
* did nothing with it. Was incorrect str/int comparision for times.
* - 2006/05/16 Shinigami: added Prop Character.Race [RACE_* Constants] to support Elfs
* - 2006/06/15 Austin: Added mobile.Privs()
* - 2007/07/09 Shinigami: added Prop Character.isUOKR [bool] - UO:KR client used?
* - 2008/07/08 Turley: Added character.movemode - returns the MoveMode like given in NPCDesc
* Added item.stackable - Is item stackable?
* - 2008/12/17 MuadDub: Added item.tile_layer - returns layer entry from tiledata/tiles.cfg
* - 2009/07/20 MuadDib: ReAdded on_facing_change() to MBR_FACING: for items.
* - 2009/08/06 MuadDib: Added gotten_by code for items.
* - 2009/08/31 MuadDib: Changed layer check on graphic change, excluding mount layer entirely.
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
* Relocation of multi related cpp/h
* - 2009/09/06 Turley: Removed isUOKR added ClientType
* - 2009/09/22 MuadDib: Rewrite for Character/NPC to use ar(), ar_mod(), ar_mod(newvalue)
* virtuals.
* - 2009/10/09 Turley: Added spellbook.spells() & .hasspell() methods
* - 2009/10/10 Turley: Added spellbook.addspell() & .removespell() methods
* - 2009/10/14 Turley: Added char.deaf() methods & char.deafened member
* - MuadDib: Squelch and Deaf members set to return the gameclock they are in effect
* till.
* - 2009/10/17 Turley: Moved PrivUpdater to charactr.cpp - Tomi
* - 2009/11/19 Turley: lightlevel now supports endless duration - Tomi
* - 2009/12/02 Turley: gargoyle race support
* - 2009/12/03 Turley: added gargoyle flying movemode
* - 2009/12/21 Turley: ._method() call fix
* multi support of methodscripts
* - 2010/01/15 Turley: (Tomi) season stuff
* - 2010/02/03 Turley: MethodScript support for mobiles
* - 2011/12/13 Tomi: Boat members MBR_COMPONENT, MBR_HULL, MBR_ROPE, MBR_SAILS, MBR_WHEEL,
* MBR_TILLER, MBR_RUDDER, MBR_STORAGE, MBR_WEAPONSLOT
* - 2012/02/02 Tomi: Added boat member MBR_MULTIID
* - 2012/03/26 Tomi: Added MBR_LASTCOORD
* - 2012/04/14 Tomi: Added MBR_FACETID for new map message packet
* - 2012/04/15 Tomi: Added MBR_EDITABLE for maps
* - 2012/06/02 Tomi: Added MBR_ACTIVE_SKILL and MBR_CASTING_SPELL for characters
*/
#include "uoscrobj.h"
#include <string>
#include "../bscript/berror.h"
#include "../bscript/dict.h"
#include "../bscript/execmodl.h"
#include "../bscript/executor.h"
#include "../bscript/impstr.h"
#include "../bscript/objmembers.h"
#include "../bscript/objmethods.h"
#include "../clib/stlutil.h"
#include "../plib/poltype.h"
#include "../plib/uconst.h"
#include "accounts/account.h"
#include "accounts/acscrobj.h"
#include "cmdlevel.h"
#include "containr.h"
#include "door.h"
#include "dynproperties.h"
#include "equipdsc.h"
#include "exscrobj.h"
#include "fnsearch.h"
#include "globals/network.h"
#include "globals/uvars.h"
#include "item/armor.h"
#include "item/equipmnt.h"
#include "item/item.h"
#include "item/itemdesc.h"
#include "item/weapon.h"
#include "lockable.h"
#include "mobile/charactr.h"
#include "mobile/corpse.h"
#include "mobile/npc.h"
#include "mobile/ufacing.h"
#include "module/guildmod.h"
#include "module/partymod.h"
#include "module/uomod.h"
#include "multi/boat.h"
#include "multi/boatcomp.h"
#include "multi/house.h"
#include "multi/multi.h"
#include "network/client.h"
#include "network/packethelper.h"
#include "network/packets.h"
#include "network/pktdef.h"
#include "npctmpl.h"
#include "polclass.h"
#include "polclock.h"
#include "proplist.h"
#include "realms/realms.h"
#include "realms/realm.h"
#include "spelbook.h"
#include "statmsg.h"
#include "syshookscript.h"
#include "tooltips.h"
#include "ufunc.h"
#include "umap.h"
#include "uobject.h"
#include "uoclient.h"
#include "uoexec.h"
#include "uworld.h"
namespace Pol
{
namespace Module
{
using namespace Bscript;
BApplicObjType euboatrefobjimp_type;
BApplicObjType emultirefobjimp_type;
BApplicObjType eitemrefobjimp_type;
BApplicObjType echaracterrefobjimp_type;
BApplicObjType echaracterequipobjimp_type;
BApplicObjType storage_area_type;
BApplicObjType menu_type;
BApplicObjType eclientrefobjimp_type;
const char* ECharacterRefObjImp::typeOf() const
{
return "MobileRef";
}
u8 ECharacterRefObjImp::typeOfInt() const
{
return OTMobileRef;
}
BObjectImp* ECharacterRefObjImp::copy() const
{
return new ECharacterRefObjImp( obj_.get() );
}
BObjectRef ECharacterRefObjImp::get_member_id( const int id )
{
BObjectImp* result = obj_->get_script_member_id( id );
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef ECharacterRefObjImp::get_member( const char* membername )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_member_id( objmember->id );
return BObjectRef( UninitObject::create() );
}
BObjectRef ECharacterRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
{
BObjectImp* result = nullptr;
if ( value->isa( BObjectImp::OTLong ) )
{
BLong* lng = static_cast<BLong*>( value );
result = obj_->set_script_member_id( id, lng->value() );
}
else if ( value->isa( BObjectImp::OTString ) )
{
String* str = static_cast<String*>( value );
result = obj_->set_script_member_id( id, str->value() );
}
else if ( value->isa( BObjectImp::OTDouble ) )
{
Double* dbl = static_cast<Double*>( value );
result = obj_->set_script_member_id_double( id, dbl->value() );
}
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef ECharacterRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_member_id( objmember->id, value, copy );
return BObjectRef( UninitObject::create() );
}
BObjectImp* ECharacterRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
bool forcebuiltin )
{
// MethodScript for npcs in npc->template_ (npctmpl.h) (aka templatebased)
// for chars in uoclient_general (uoclient.h) (aka one global definition)
if ( obj_->orphan() )
return new BError( "That object no longer exists" );
ObjMethod* mth = getObjMethod( id );
if ( mth->overridden && !forcebuiltin )
{
BObjectImp* imp = obj_->custom_script_method( mth->code, ex );
if ( imp )
return imp;
}
BObjectImp* imp = obj_->script_method_id( id, ex );
if ( imp != nullptr )
return imp;
return base::call_polmethod_id( id, ex );
}
BObjectImp* ECharacterRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
{
// MethodScript for npcs in npc->template_ (npctmpl.h) (aka templatebased)
// for chars in uoclient_general (uoclient.h) (aka one global definition)
bool forcebuiltin{Executor::builtinMethodForced( methodname )};
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
BObjectImp* imp = obj_->custom_script_method( methodname, ex );
if ( imp )
return imp;
return base::call_polmethod( methodname, ex );
}
bool ECharacterRefObjImp::isTrue() const
{
return ( !obj_->orphan() && obj_->logged_in() );
}
bool ECharacterRefObjImp::operator==( const BObjectImp& objimp ) const
{
if ( objimp.isa( BObjectImp::OTApplicObj ) )
{
const BApplicObjBase* aob =
Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
if ( aob->object_type() == &echaracterrefobjimp_type )
{
const ECharacterRefObjImp* chrref_imp =
Clib::explicit_cast<const ECharacterRefObjImp*, const BApplicObjBase*>( aob );
return ( chrref_imp->obj_->serial == obj_->serial );
}
else
return false;
}
else if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
return false;
}
bool ECharacterRefObjImp::operator<( const BObjectImp& objimp ) const
{
if ( objimp.isa( BObjectImp::OTApplicObj ) )
{
const BApplicObjBase* aob =
Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
if ( aob->object_type() == &echaracterrefobjimp_type )
{
const ECharacterRefObjImp* chrref_imp =
Clib::explicit_cast<const ECharacterRefObjImp*, const BApplicObjBase*>( aob );
return ( chrref_imp->obj_->serial < obj_->serial );
}
else if ( aob->object_type() == &eitemrefobjimp_type )
return true;
return false;
}
return base::operator<( objimp );
}
const char* EOfflineCharacterRefObjImp::typeOf() const
{
return "OfflineMobileRef";
}
u8 EOfflineCharacterRefObjImp::typeOfInt() const
{
return OTOfflineMobileRef;
}
BObjectImp* EOfflineCharacterRefObjImp::copy() const
{
return new EOfflineCharacterRefObjImp( obj_.get() );
}
bool EOfflineCharacterRefObjImp::isTrue() const
{
return ( !obj_->orphan() );
}
const char* EItemRefObjImp::typeOf() const
{
return "ItemRef";
}
u8 EItemRefObjImp::typeOfInt() const
{
return OTItemRef;
}
BObjectImp* EItemRefObjImp::copy() const
{
return new EItemRefObjImp( obj_.get() );
}
BObjectRef EItemRefObjImp::get_member_id( const int id )
{
BObjectImp* result = obj_->get_script_member_id( id );
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef EItemRefObjImp::get_member( const char* membername )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_member_id( objmember->id );
return BObjectRef( UninitObject::create() );
}
BObjectRef EItemRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
{
BObjectImp* result = nullptr;
if ( value->isa( BObjectImp::OTLong ) )
{
BLong* lng = static_cast<BLong*>( value );
result = obj_->set_script_member_id( id, lng->value() );
}
else if ( value->isa( BObjectImp::OTString ) )
{
String* str = static_cast<String*>( value );
result = obj_->set_script_member_id( id, str->value() );
}
else if ( value->isa( BObjectImp::OTDouble ) )
{
Double* dbl = static_cast<Double*>( value );
result = obj_->set_script_member_id_double( id, dbl->value() );
}
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef EItemRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_member_id( objmember->id, value, copy );
return BObjectRef( UninitObject::create() );
}
BObjectImp* EItemRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
bool forcebuiltin )
{
if ( obj_->orphan() )
return new BError( "That object no longer exists" );
ObjMethod* mth = getObjMethod( id );
if ( mth->overridden && !forcebuiltin )
{
BObjectImp* imp = obj_->custom_script_method( mth->code, ex );
if ( imp )
return imp;
}
BObjectImp* imp = obj_->script_method_id( id, ex );
if ( imp != nullptr )
return imp;
return base::call_polmethod_id( id, ex );
}
BObjectImp* EItemRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
{
bool forcebuiltin{Executor::builtinMethodForced( methodname )};
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
Items::Item* item = obj_.get();
BObjectImp* imp = item->custom_script_method( methodname, ex );
if ( imp )
return imp;
return base::call_polmethod( methodname, ex );
}
bool EItemRefObjImp::isTrue() const
{
return ( !obj_->orphan() );
}
bool EItemRefObjImp::operator==( const BObjectImp& objimp ) const
{
if ( objimp.isa( BObjectImp::OTApplicObj ) )
{
const BApplicObjBase* aob =
Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
if ( aob->object_type() == &eitemrefobjimp_type )
{
const EItemRefObjImp* itemref_imp =
Clib::explicit_cast<const EItemRefObjImp*, const BApplicObjBase*>( aob );
return ( itemref_imp->obj_->serial == obj_->serial );
}
return false;
}
else if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
return false;
}
bool EItemRefObjImp::operator<( const BObjectImp& objimp ) const
{
if ( objimp.isa( BObjectImp::OTApplicObj ) )
{
const BApplicObjBase* aob =
Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
if ( aob->object_type() == &eitemrefobjimp_type )
{
const EItemRefObjImp* itemref_imp =
Clib::explicit_cast<const EItemRefObjImp*, const BApplicObjBase*>( aob );
return ( itemref_imp->obj_->serial < obj_->serial );
}
return ( &eitemrefobjimp_type < aob->object_type() );
}
return base::operator<( objimp );
}
const char* EUBoatRefObjImp::typeOf() const
{
return "BoatRef";
}
u8 EUBoatRefObjImp::typeOfInt() const
{
return OTBoatRef;
}
BObjectImp* EUBoatRefObjImp::copy() const
{
return new EUBoatRefObjImp( obj_.get() );
}
BObjectRef EUBoatRefObjImp::get_member_id( const int id )
{
BObjectImp* result = obj_->get_script_member_id( id );
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef EUBoatRefObjImp::get_member( const char* membername )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_member_id( objmember->id );
return BObjectRef( UninitObject::create() );
}
BObjectRef EUBoatRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
{
BObjectImp* result = nullptr;
if ( value->isa( BObjectImp::OTLong ) )
{
BLong* lng = static_cast<BLong*>( value );
result = obj_->set_script_member_id( id, lng->value() );
}
else if ( value->isa( BObjectImp::OTString ) )
{
String* str = static_cast<String*>( value );
result = obj_->set_script_member_id( id, str->value() );
}
else if ( value->isa( BObjectImp::OTDouble ) )
{
Double* dbl = static_cast<Double*>( value );
result = obj_->set_script_member_id_double( id, dbl->value() );
}
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef EUBoatRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_member_id( objmember->id, value, copy );
return BObjectRef( UninitObject::create() );
}
BObjectImp* EUBoatRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
bool forcebuiltin )
{
if ( obj_->orphan() )
return new BError( "That object no longer exists" );
ObjMethod* mth = getObjMethod( id );
if ( mth->overridden && !forcebuiltin )
{
BObjectImp* imp = obj_->custom_script_method( mth->code, ex );
if ( imp )
return imp;
}
BObjectImp* imp = obj_->script_method_id( id, ex );
if ( imp != nullptr )
return imp;
return base::call_polmethod_id( id, ex );
}
BObjectImp* EUBoatRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
{
bool forcebuiltin{Executor::builtinMethodForced( methodname )};
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
return base::call_polmethod( methodname, ex );
}
bool EUBoatRefObjImp::isTrue() const
{
return ( !obj_->orphan() );
}
bool EUBoatRefObjImp::operator==( const BObjectImp& objimp ) const
{
if ( objimp.isa( BObjectImp::OTApplicObj ) )
{
const BApplicObjBase* aob =
Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
if ( aob->object_type() == &euboatrefobjimp_type )
{
const EUBoatRefObjImp* boatref_imp =
Clib::explicit_cast<const EUBoatRefObjImp*, const BApplicObjBase*>( aob );
return ( boatref_imp->obj_->serial == obj_->serial );
}
return false;
}
else if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
return false;
}
BObjectImp* EMultiRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
{
bool forcebuiltin{Executor::builtinMethodForced( methodname )};
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
Multi::UMulti* multi = obj_.get();
BObjectImp* imp = multi->custom_script_method( methodname, ex );
if ( imp )
return imp;
return base::call_polmethod( methodname, ex );
}
BObjectImp* EMultiRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
bool forcebuiltin )
{
Multi::UMulti* multi = obj_.get();
if ( multi->orphan() )
return new BError( "That object no longer exists" );
ObjMethod* mth = getObjMethod( id );
if ( mth->overridden && !forcebuiltin )
{
BObjectImp* imp = multi->custom_script_method( mth->code, ex );
if ( imp )
return imp;
}
BObjectImp* imp = multi->script_method_id( id, ex );
if ( imp != nullptr )
return imp;
return base::call_polmethod_id( id, ex, forcebuiltin );
}
const char* EMultiRefObjImp::typeOf() const
{
return "MultiRef";
}
u8 EMultiRefObjImp::typeOfInt() const
{
return OTMultiRef;
}
BObjectImp* EMultiRefObjImp::copy() const
{
return new EMultiRefObjImp( obj_.get() );
}
BObjectRef EMultiRefObjImp::get_member_id( const int id )
{
BObjectImp* result = obj_->get_script_member_id( id );
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef EMultiRefObjImp::get_member( const char* membername )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_member_id( objmember->id );
return BObjectRef( UninitObject::create() );
}
BObjectRef EMultiRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
{
BObjectImp* result = nullptr;
if ( value->isa( BObjectImp::OTLong ) )
{
BLong* lng = static_cast<BLong*>( value );
result = obj_->set_script_member_id( id, lng->value() );
}
else if ( value->isa( BObjectImp::OTString ) )
{
String* str = static_cast<String*>( value );
result = obj_->set_script_member_id( id, str->value() );
}
else if ( value->isa( BObjectImp::OTDouble ) )
{
Double* dbl = static_cast<Double*>( value );
result = obj_->set_script_member_id_double( id, dbl->value() );
}
if ( result != nullptr )
return BObjectRef( result );
return BObjectRef( UninitObject::create() );
}
BObjectRef EMultiRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_member_id( objmember->id, value, copy );
return BObjectRef( UninitObject::create() );
}
bool EMultiRefObjImp::isTrue() const
{
return ( !obj_->orphan() );
}
bool EMultiRefObjImp::operator==( const BObjectImp& objimp ) const
{
if ( objimp.isa( BObjectImp::OTApplicObj ) )
{
const BApplicObjBase* aob =
Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
if ( aob->object_type() == &emultirefobjimp_type )
{
const EMultiRefObjImp* multiref_imp =
Clib::explicit_cast<const EMultiRefObjImp*, const BApplicObjBase*>( aob );
return ( multiref_imp->obj_->serial == obj_->serial );
}
return false;
}
else if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
return false;
}
} // namespace Module
namespace Core
{
using namespace Bscript;
BObjectImp* UObject::get_script_member_id( const int id ) const
{
if ( orphan() )
return new UninitObject;
switch ( id )
{
case MBR_X:
return new BLong( pos().x() );
break;
case MBR_Y:
return new BLong( pos().y() );
break;
case MBR_Z:
return new BLong( pos().z() );
break;
case MBR_NAME:
return new String( name() );
break;
case MBR_OBJTYPE:
return new BLong( objtype_ );
break;
case MBR_GRAPHIC:
return new BLong( graphic );
break;
case MBR_SERIAL:
return new BLong( serial );
break;
case MBR_COLOR:
return new BLong( color );
break;
case MBR_HEIGHT:
return new BLong( height );
break;
case MBR_FACING:
return new BLong( facing );
break;
case MBR_DIRTY:
return new BLong( dirty() ? 1 : 0 );
break;
case MBR_WEIGHT:
return new BLong( weight() );
break;
case MBR_MULTI:
{
Multi::UMulti* multi = this->supporting_multi();
if ( multi != nullptr )
return multi->make_ref();
else
return new BLong( 0 );
}
break;
case MBR_REALM:
if ( toplevel_pos().realm() != nullptr )
return new String( toplevel_pos().realm()->name() );
else
return new BError( "object does not belong to a realm." );
break;
case MBR_SPECIFIC_NAME:
return new BLong( specific_name() );
default:
return nullptr;
}
}
BObjectImp* UObject::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* UObject::set_script_member_id( const int id, const std::string& value )
{
if ( orphan() )
return new UninitObject;
set_dirty();
switch ( id )
{
case MBR_NAME:
if ( ismobile() && ( value.empty() || isspace( value[0] ) ) )
return new BError( "mobile.name must not be empty, and must not begin with a space" );
setname( value );
return new String( name() );
break;
default:
return nullptr;
}
}
BObjectImp* UObject::set_script_member( const char* membername, const std::string& value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UObject::set_script_member_id( const int id, int value )
{
if ( orphan() )
return new UninitObject;
set_dirty();
switch ( id )
{
case MBR_GRAPHIC:
setgraphic( static_cast<unsigned short>( value ) );
return new BLong( graphic );
case MBR_COLOR:
{
bool res = setcolor( static_cast<unsigned short>( value ) );
if ( !res ) // TODO log?
return new BError( "Invalid color value " + Clib::hexint( value ) );
return new BLong( color );
}
default:
return nullptr;
}
}
BObjectImp* UObject::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UObject::set_script_member_id_double( const int /*id*/, double /*value*/ )
{
set_dirty();
return nullptr;
}
BObjectImp* UObject::set_script_member_double( const char* membername, double value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id_double( objmember->id, value );
return nullptr;
}
} // namespace Core
namespace Items
{
using namespace Bscript;
BObjectImp* Item::get_script_member_id( const int id ) const
{
BObjectImp* imp = base::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_AMOUNT:
return new BLong( amount_ );
break;
case MBR_LAYER:
return new BLong( layer );
break;
case MBR_TILE_LAYER:
return new BLong( tile_layer );
break;
case MBR_CONTAINER:
if ( container != nullptr )
return container->make_ref();
return new BLong( 0 );
break;
case MBR_USESCRIPT:
return new String( on_use_script_ );
break;
case MBR_EQUIPSCRIPT:
return new String( equip_script_ );
break;
case MBR_UNEQUIPSCRIPT:
return new String( unequip_script_ );
break;
case MBR_DESC:
return new String( description() );
break;
case MBR_MOVABLE:
return new BLong( movable() ? 1 : 0 );
break;
case MBR_INVISIBLE:
return new BLong( invisible() ? 1 : 0 );
break;
case MBR_DECAYAT:
return new BLong( decayat_gameclock_ );
break;
case MBR_SELLPRICE:
return new BLong( sellprice() );
break;
case MBR_BUYPRICE:
return new BLong( buyprice() );
break;
case MBR_NEWBIE:
return new BLong( newbie() ? 1 : 0 );
break;
case MBR_INSURED:
return new BLong( insured() ? 1 : 0 );
break;
case MBR_ITEM_COUNT:
return new BLong( item_count() );
break;
case MBR_STACKABLE:
return new BLong( stackable() ? 1 : 0 );
break;
case MBR_SAVEONEXIT:
return new BLong( saveonexit() );
break;
case MBR_FIRE_RESIST:
return new BLong( fire_resist().sum() );
break;
case MBR_COLD_RESIST:
return new BLong( cold_resist().sum() );
break;
case MBR_ENERGY_RESIST:
return new BLong( energy_resist().sum() );
break;
case MBR_POISON_RESIST:
return new BLong( poison_resist().sum() );
break;
case MBR_PHYSICAL_RESIST:
return new BLong( physical_resist().sum() );
break;
case MBR_LOWER_REAG_COST:
return new BLong( lower_reagent_cost().sum() );
break;
case MBR_SPELL_DAMAGE_INCREASE:
return new BLong( spell_damage_increase().sum() );
break;
case MBR_FASTER_CASTING:
return new BLong( faster_casting().sum() );
break;
case MBR_FASTER_CAST_RECOVERY:
return new BLong( faster_casting().sum() );
break;
case MBR_DEFENCE_CHANCE_INCREASE:
return new BLong( defence_increase().sum() );
break;
case MBR_DEFENCE_CHANCE_INCREASE_CAP:
return new BLong( defence_increase_cap().sum() );
break;
case MBR_LOWER_MANA_COST:
return new BLong( lower_mana_cost().sum() );
break;
case MBR_HIT_CHANCE:
return new BLong( hit_chance().sum() );
break;
case MBR_FIRE_RESIST_CAP:
return new BLong( fire_resist_cap().sum() );
break;
case MBR_COLD_RESIST_CAP:
return new BLong( cold_resist_cap().sum() );
break;
case MBR_ENERGY_RESIST_CAP:
return new BLong( energy_resist_cap().sum() );
break;
case MBR_POISON_RESIST_CAP:
return new BLong( poison_resist_cap().sum() );
break;
case MBR_PHYSICAL_RESIST_CAP:
return new BLong( physical_resist_cap().sum() );
break;
case MBR_LUCK:
return new BLong( luck().sum() );
break;
case MBR_SWING_SPEED_INCREASE:
return new BLong( swing_speed_increase().sum() );
break;
case MBR_FIRE_RESIST_MOD:
return new BLong( fire_resist().mod );
break;
case MBR_COLD_RESIST_MOD:
return new BLong( cold_resist().mod );
break;
case MBR_ENERGY_RESIST_MOD:
return new BLong( energy_resist().mod );
break;
case MBR_POISON_RESIST_MOD:
return new BLong( poison_resist().mod );
break;
case MBR_PHYSICAL_RESIST_MOD:
return new BLong( physical_resist().mod );
break;
case MBR_FIRE_DAMAGE:
return new BLong( fire_damage().sum() );
break;
case MBR_COLD_DAMAGE:
return new BLong( cold_damage().sum() );
break;
case MBR_ENERGY_DAMAGE:
return new BLong( energy_damage().sum() );
break;
case MBR_POISON_DAMAGE:
return new BLong( poison_damage().sum() );
break;
case MBR_PHYSICAL_DAMAGE:
return new BLong( physical_damage().sum() );
break;
case MBR_FIRE_DAMAGE_MOD:
return new BLong( fire_damage().mod );
break;
case MBR_COLD_DAMAGE_MOD:
return new BLong( cold_damage().mod );
break;
case MBR_ENERGY_DAMAGE_MOD:
return new BLong( energy_damage().mod );
break;
case MBR_POISON_DAMAGE_MOD:
return new BLong( poison_damage().mod );
break;
case MBR_PHYSICAL_DAMAGE_MOD:
return new BLong( physical_damage().mod );
break;
case MBR_LOWER_REAG_COST_MOD:
return new BLong( lower_reagent_cost().mod );
break;
case MBR_SPELL_DAMAGE_INCREASE_MOD:
return new BLong( spell_damage_increase().mod );
break;
case MBR_FASTER_CASTING_MOD:
return new BLong( faster_casting().mod );
break;
case MBR_FASTER_CAST_RECOVERY_MOD:
return new BLong( faster_casting().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_MOD:
return new BLong( defence_increase().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
return new BLong( defence_increase_cap().mod );
break;
case MBR_LOWER_MANA_COST_MOD:
return new BLong( lower_mana_cost().mod );
break;
case MBR_HIT_CHANCE_MOD:
return new BLong( hit_chance().mod );
break;
case MBR_FIRE_RESIST_CAP_MOD:
return new BLong( fire_resist_cap().mod );
break;
case MBR_COLD_RESIST_CAP_MOD:
return new BLong( cold_resist_cap().mod );
break;
case MBR_ENERGY_RESIST_CAP_MOD:
return new BLong( energy_resist_cap().mod );
break;
case MBR_POISON_RESIST_CAP_MOD:
return new BLong( poison_resist_cap().mod );
break;
case MBR_PHYSICAL_RESIST_CAP_MOD:
return new BLong( physical_resist_cap().mod );
break;
case MBR_LUCK_MOD:
return new BLong( luck().mod );
break;
case MBR_SWING_SPEED_INCREASE_MOD:
return new BLong( swing_speed_increase().mod );
break;
case MBR_GETGOTTENBY:
if ( has_gotten_by() )
return new Module::ECharacterRefObjImp( gotten_by() );
return new BError( "Gotten By nullptr" );
break;
case MBR_PROCESS:
{
Module::UOExecutorModule* proc = process();
if ( proc )
{
Core::UOExecutor* executor = static_cast<Core::UOExecutor*>( &proc->exec );
return new Core::ScriptExObjImp( executor );
}
return new BError( "No script running" );
break;
}
case MBR_DOUBLECLICKRANGE:
{
const ItemDesc& itemdesc = this->itemdesc();
return new BLong( itemdesc.doubleclick_range );
break;
}
case MBR_QUALITY:
return new Double( quality() );
break;
case MBR_HP:
return new BLong( hp_ );
break;
case MBR_MAXHP_MOD:
return new BLong( maxhp_mod() );
break;
case MBR_MAXHP:
return new BLong( static_cast<int>( maxhp() * quality() ) );
break;
case MBR_NAME_SUFFIX:
return new String( name_suffix() );
break;
case MBR_HOUSE:
if ( house() != nullptr )
return house()->make_ref();
return new BError( "This is a not component of any house" );
break;
case MBR_NO_DROP:
return new BLong( no_drop() );
default:
return nullptr;
}
}
BObjectImp* Item::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* Item::set_script_member_id( const int id, const std::string& value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_USESCRIPT:
on_use_script_ = value;
return new String( value );
case MBR_EQUIPSCRIPT:
equip_script_ = value;
return new String( value );
case MBR_UNEQUIPSCRIPT:
unequip_script_ = value;
return new String( value );
case MBR_NAME_SUFFIX:
set_dirty();
increv();
send_object_cache_to_inrange( this );
name_suffix( value );
return new String( value );
default:
return nullptr;
}
}
BObjectImp* Item::set_script_member( const char* membername, const std::string& value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* Item::set_script_member_id( const int id, int value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_MOVABLE:
restart_decay_timer();
movable( value ? true : false );
increv();
return new BLong( movable() );
case MBR_INVISIBLE:
restart_decay_timer();
invisible( value ? true : false );
increv();
return new BLong( invisible() );
case MBR_DECAYAT:
decayat_gameclock_ = value;
return new BLong( decayat_gameclock_ );
case MBR_SELLPRICE:
sellprice( value );
return new BLong( value );
case MBR_BUYPRICE:
buyprice( value );
return new BLong( value );
case MBR_NEWBIE:
restart_decay_timer();
newbie( value ? true : false );
increv();
return new BLong( newbie() );
case MBR_INSURED:
restart_decay_timer();
insured( value ? true : false );
increv();
return new BLong( insured() );
case MBR_FACING:
setfacing( (u8)value );
return new BLong( facing );
case MBR_SAVEONEXIT:
saveonexit( value ? true : false );
return new BLong( saveonexit() );
case MBR_FIRE_RESIST_MOD:
fire_resist( fire_resist().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( fire_resist().mod );
break;
case MBR_COLD_RESIST_MOD:
cold_resist( cold_resist().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( cold_resist().mod );
break;
case MBR_ENERGY_RESIST_MOD:
energy_resist( energy_resist().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( energy_resist().mod );
break;
case MBR_POISON_RESIST_MOD:
poison_resist( poison_resist().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( poison_resist().mod );
break;
case MBR_PHYSICAL_RESIST_MOD:
physical_resist( physical_resist().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( physical_resist().mod );
break;
case MBR_FIRE_RESIST_CAP_MOD:
fire_resist_cap( fire_resist_cap().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( fire_resist_cap().mod );
break;
case MBR_COLD_RESIST_CAP_MOD:
cold_resist_cap( cold_resist_cap().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( cold_resist_cap().mod );
break;
case MBR_ENERGY_RESIST_CAP_MOD:
energy_resist_cap( energy_resist_cap().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( energy_resist_cap().mod );
break;
case MBR_POISON_RESIST_CAP_MOD:
poison_resist_cap( poison_resist_cap().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( poison_resist_cap().mod );
break;
case MBR_PHYSICAL_RESIST_CAP_MOD:
physical_resist_cap( physical_resist_cap().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( physical_resist_cap().mod );
break;
case MBR_FIRE_DAMAGE_MOD:
fire_damage( fire_damage().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( fire_damage().mod );
break;
case MBR_COLD_DAMAGE_MOD:
cold_damage( cold_damage().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( cold_damage().mod );
break;
case MBR_ENERGY_DAMAGE_MOD:
energy_damage( energy_damage().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( energy_damage().mod );
break;
case MBR_POISON_DAMAGE_MOD:
poison_damage( poison_damage().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( poison_damage().mod );
break;
case MBR_PHYSICAL_DAMAGE_MOD:
physical_damage( physical_damage().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( physical_damage().mod );
break;
case MBR_LOWER_REAG_COST_MOD:
lower_reagent_cost( lower_reagent_cost().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( lower_reagent_cost().mod );
break;
case MBR_SPELL_DAMAGE_INCREASE_MOD:
spell_damage_increase( spell_damage_increase().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( spell_damage_increase().mod );
break;
case MBR_FASTER_CASTING_MOD:
faster_casting( faster_casting().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( faster_casting().mod );
break;
case MBR_FASTER_CAST_RECOVERY_MOD:
faster_cast_recovery( faster_cast_recovery().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( faster_cast_recovery().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_MOD:
defence_increase( defence_increase().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( defence_increase().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
defence_increase_cap( defence_increase_cap().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( defence_increase_cap().mod );
break;
case MBR_LOWER_MANA_COST_MOD:
lower_mana_cost( lower_mana_cost().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( lower_mana_cost().mod );
break;
case MBR_HITCHANCE_MOD: // to be made redundant in the future
case MBR_HIT_CHANCE_MOD:
hit_chance( hit_chance().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( hit_chance().mod );
break;
case MBR_LUCK_MOD:
luck( luck().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( luck().mod );
break;
case MBR_SWING_SPEED_INCREASE_MOD:
swing_speed_increase( swing_speed_increase().setAsMod( static_cast<short>( value ) ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
return new BLong( swing_speed_increase().mod );
break;
case MBR_QUALITY:
quality( double( value ) );
return new Double( double( value ) );
break;
case MBR_HP:
hp_ = static_cast<unsigned short>( value );
if ( this->isa( Core::UOBJ_CLASS::CLASS_ARMOR ) )
{
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
}
return new BLong( hp_ );
case MBR_MAXHP_MOD:
this->maxhp_mod( static_cast<s16>( value ) );
if ( this->isa( Core::UOBJ_CLASS::CLASS_ARMOR ) )
{
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
chr->refresh_ar();
}
}
}
return new BLong( value );
case MBR_NO_DROP:
no_drop( value ? true : false );
return new BLong( no_drop() );
default:
return nullptr;
}
}
BObjectImp* Item::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* Item::set_script_member_id_double( const int id, double value )
{
BObjectImp* imp = base::set_script_member_id_double( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_QUALITY:
quality( value );
return new Double( value );
default:
return nullptr;
}
}
BObjectImp* Item::set_script_member_double( const char* membername, double value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id_double( objmember->id, value );
return nullptr;
}
BObjectImp* Item::script_method_id( const int id, Core::UOExecutor& ex )
{
BObjectImp* imp = base::script_method_id( id, ex );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MTH_SPLITSTACK_AT:
{
unsigned short amt;
Core::Pos4d newpos;
Item* new_stack( nullptr );
u16 item_amount = this->getamount();
if ( !ex.hasParams( 5 ) )
return new BError( "Not enough parameters" );
else if ( !ex.getPos4dParam( 0, 1, 2, 3, &newpos ) )
return new BError( "Invalid parameter type" );
else if ( !ex.getParam( 4, amt ) )
return new BError( "No amount specified to pull from existing stack" );
else if ( amt > this->getamount() )
return new BError( "Amount must be less than or equal to the stack amount" );
else if ( amt < 1 )
return new BError( "Amount was less than 1" );
else if ( this->inuse() )
return new BError( "Item is in use" );
// Check first if the item is non-stackable and just force stacked with CreateItemInInventory
if ( !this->stackable() && amt > 1 )
{
unsigned short i;
for ( i = 1; i <= amt; i++ )
{
if ( this->getamount() == 1 )
new_stack = this->clone();
else
new_stack = this->remove_part_of_stack( 1 );
Core::Pos4d oldpos = new_stack->pos();
new_stack->setposition( newpos );
add_item_to_world( new_stack );
move_item( new_stack, newpos, oldpos );
update_item_to_inrange( new_stack );
}
if ( this->getamount() == 1 )
destroy_item( this );
else
update_item_to_inrange( this );
if ( new_stack != nullptr )
return new Module::EItemRefObjImp( new_stack );
return nullptr;
}
if ( amt == this->getamount() )
new_stack = this->clone();
else
new_stack = this->remove_part_of_stack( amt );
new_stack->setamount( amt );
Core::Pos4d oldpos = new_stack->pos();
new_stack->setposition( newpos );
add_item_to_world( new_stack );
move_item( new_stack, newpos, oldpos );
update_item_to_inrange( new_stack );
if ( amt == item_amount )
destroy_item( this );
else
update_item_to_inrange( this );
return new Module::EItemRefObjImp( new_stack );
break;
}
case MTH_SPLITSTACK_INTO:
{
unsigned short amt;
Item* cont_item;
if ( !ex.hasParams( 2 ) )
return new BError( "Not enough parameters" );
else if ( !ex.getItemParam( 0, cont_item ) )
return new BError( "No container specified" );
else if ( !ex.getParam( 1, amt ) )
return new BError( "No amount specified to pull from existing stack" );
else if ( amt > this->getamount() )
return new BError( "Amount must be less than or equal to stack amount" );
else if ( amt < 1 )
return new BError( "Amount was less than 1" );
else if ( this->inuse() )
return new BError( "Item is in use" );
else if ( !cont_item->isa( Core::UOBJ_CLASS::CLASS_CONTAINER ) )
return new BError( "Non-container selected as target" );
Core::UContainer* newcontainer = static_cast<Core::UContainer*>( cont_item );
// Check first if the item is non-stackable and just force stacked with CreateItemInInventory
Item* new_stack( nullptr );
u16 item_amount = this->getamount();
if ( !this->stackable() && amt > 1 )
{
for ( unsigned short i = 1; i <= amt; i++ )
{
if ( this->getamount() == 1 )
new_stack = this->clone();
else
new_stack = this->remove_part_of_stack( 1 );
bool can_insert = newcontainer->can_insert_add_item(
nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
if ( !can_insert )
{
// Put new_stack back with the original stack
if ( new_stack != this )
this->add_to_self( new_stack );
return new BError( "Could not insert new stack into container" );
}
newcontainer->add_at_random_location( new_stack );
update_item_to_inrange( new_stack );
UpdateCharacterWeight( new_stack );
newcontainer->on_insert_add_item( nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
}
if ( this->getamount() == 1 )
destroy_item( this );
else
update_item_to_inrange( this );
if ( new_stack != nullptr )
return new Module::EItemRefObjImp( new_stack );
return nullptr;
}
if ( amt == this->getamount() )
new_stack = this->clone();
else
new_stack = this->remove_part_of_stack( amt );
auto create_new_stack = [&]() -> BObjectImp* {
bool can_insert =
newcontainer->can_insert_add_item( nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
if ( !can_insert )
{
// Put newstack back with the original stack
if ( new_stack != this )
this->add_to_self( new_stack );
return new BError( "Could not insert new stack into container" );
}
newcontainer->add_at_random_location( new_stack );
new_stack->setamount( amt );
update_item_to_inrange( new_stack );
UpdateCharacterWeight( new_stack );
newcontainer->on_insert_add_item( nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
if ( amt == item_amount )
destroy_item( this );
else
update_item_to_inrange( this );
return new Module::EItemRefObjImp( new_stack );
};
int add_to_existing_stack;
if ( !ex.hasParams( 3 ) ||
( ex.getParam( 2, add_to_existing_stack ) && add_to_existing_stack != 0 ) )
{
Item* existing_stack = newcontainer->find_addable_stack( new_stack );
if ( existing_stack != nullptr && new_stack->stackable() )
{
if ( !newcontainer->can_insert_increase_stack( nullptr, Core::UContainer::MT_CORE_MOVED,
existing_stack, new_stack->getamount(),
new_stack ) )
{
if ( new_stack != this )
this->add_to_self( new_stack );
return new BError( "Could not add to existing stack" );
}
}
else
return create_new_stack();
u16 amount = new_stack->getamount();
existing_stack->add_to_self( new_stack );
update_item_to_inrange( existing_stack );
UpdateCharacterWeight( existing_stack );
newcontainer->on_insert_increase_stack( nullptr, Core::UContainer::MT_CORE_MOVED,
existing_stack, amount );
if ( amt == item_amount )
destroy_item( this );
else
update_item_to_inrange( this );
return new Module::EItemRefObjImp( existing_stack );
}
else
return create_new_stack();
break;
}
case MTH_HAS_EXISTING_STACK:
{
Item* cont = nullptr;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough params" );
else if ( !ex.getItemParam( 0, cont ) )
return new BError( "No container specified" );
else if ( this->inuse() )
return new BError( "Item is in use" );
else if ( !cont->isa( Core::UOBJ_CLASS::CLASS_CONTAINER ) )
return new BError( "Non-container selected as target" );
Core::UContainer* stackcontainer = static_cast<Core::UContainer*>( cont );
Item* existing_stack = stackcontainer->find_addable_stack( this );
if ( existing_stack != nullptr )
return new Module::EItemRefObjImp( existing_stack );
return nullptr;
break;
}
default:
return nullptr;
}
}
BObjectImp* Item::script_method( const char* methodname, Core::UOExecutor& ex )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, ex );
return nullptr;
}
BObjectImp* Item::custom_script_method( const char* methodname, Core::UOExecutor& ex )
{
const ItemDesc& id = itemdesc();
if ( id.method_script != nullptr )
{
unsigned PC;
if ( id.method_script->FindExportedFunction(
methodname, static_cast<unsigned int>( ex.numParams() + 1 ), PC ) )
return id.method_script->call( PC, make_ref(), ex.fparams );
}
return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
}
BObject Item::call_custom_method( const char* methodname )
{
// no systemhook needed used for openbook uo module function
BObjectImpRefVec noparams;
return call_custom_method( methodname, noparams );
}
BObject Item::call_custom_method( const char* methodname, BObjectImpRefVec& pmore )
{
// no systemhook needed used for openbook uo module function
const ItemDesc& id = itemdesc();
if ( id.method_script != nullptr )
{
unsigned PC;
if ( id.method_script->FindExportedFunction(
methodname, static_cast<unsigned int>( pmore.size() + 1 ), PC ) )
return id.method_script->call( PC, new Module::EItemRefObjImp( this ), pmore );
else
{
std::string message;
message = "Method script for objtype " + id.objtype_description() +
" does not export function " + std::string( methodname ) + " taking " +
Clib::tostring( pmore.size() + 1 ) + " parameters";
BError* err = new BError( message );
return BObject( err );
}
}
return BObject( new BError( "No method script defined for " + id.objtype_description() ) );
}
BObjectImp* Item::make_ref()
{
return new Module::EItemRefObjImp( this );
}
} // namespace Items
namespace Mobile
{
using namespace Bscript;
class ARUpdater
{
public:
static void on_change( Character* chr )
{
chr->refresh_ar(); // FIXME inefficient
// if (chr->client != nullptr) // already send in refresh_ar()
//{
// send_full_statmsg( chr->client, chr );
//}
}
};
BObjectImp* Character::make_ref()
{
return new Module::ECharacterRefObjImp( this );
}
BObjectImp* Character::make_offline_ref()
{
return new Module::EOfflineCharacterRefObjImp( this );
}
BObjectImp* Character::get_script_member_id( const int id ) const
{
BObjectImp* imp = base::get_script_member_id( id );
if ( imp != nullptr )
return imp;
auto EnforceCaps = []( s16 baseValue, const s16 capValue ) -> s16 {
const bool ignore_caps = Core::settingsManager.ssopt.core_ignores_defence_caps;
if ( !ignore_caps )
baseValue = std::min( baseValue, capValue );
return baseValue;
};
switch ( id )
{
case MBR_WARMODE:
return new BLong( warmode() );
break;
case MBR_GENDER:
return new BLong( gender );
break;
case MBR_RACE:
return new BLong( race );
break;
case MBR_TRUEOBJTYPE:
return new BLong( trueobjtype );
break;
case MBR_TRUECOLOR:
return new BLong( truecolor );
break;
case MBR_AR_MOD:
return new BLong( ar_mod() );
break;
case MBR_DELAY_MOD:
return new BLong( delay_mod() );
break;
case MBR_HIDDEN:
return new BLong( hidden() ? 1 : 0 );
break;
case MBR_CONCEALED:
return new BLong( concealed() );
break;
case MBR_FROZEN:
return new BLong( frozen() ? 1 : 0 );
break;
case MBR_PARALYZED:
return new BLong( paralyzed() ? 1 : 0 );
break;
case MBR_POISONED:
return new BLong( poisoned() ? 1 : 0 );
break;
case MBR_STEALTHSTEPS:
return new BLong( stealthsteps_ );
break;
case MBR_MOUNTEDSTEPS:
return new BLong( mountedsteps_ );
break;
case MBR_SQUELCHED:
return new BLong( squelched() ? 1 : 0 );
break;
case MBR_DEAD:
return new BLong( dead() );
break;
case MBR_AR:
return new BLong( ar() );
break;
case MBR_BACKPACK:
{
Items::Item* bp = backpack();
if ( bp != nullptr )
return bp->make_ref();
return new BError( "That has no backpack" );
break;
}
case MBR_TRADEWINDOW:
{
Core::UContainer* tw = trading_cont.get();
if ( trading_with != nullptr )
return tw->make_ref();
return new BError( "That has no active tradewindow" );
break;
}
case MBR_WEAPON:
if ( weapon != nullptr )
return weapon->make_ref();
return new BLong( 0 );
break;
case MBR_SHIELD:
if ( shield != nullptr )
return shield->make_ref();
return new BLong( 0 );
break;
case MBR_ACCTNAME:
if ( acct != nullptr )
return new String( acct->name() );
return new BError( "Not attached to an account" );
break;
case MBR_ACCT:
if ( acct != nullptr )
return new Accounts::AccountObjImp( Accounts::AccountPtrHolder( acct ) );
return new BError( "Not attached to an account" );
break;
case MBR_CMDLEVEL:
return new BLong( cmdlevel() );
break;
case MBR_CMDLEVELSTR:
return new String( Core::gamestate.cmdlevels[cmdlevel()].name );
break;
case MBR_CRIMINAL:
return new BLong( is_criminal() ? 1 : 0 );
break;
case MBR_TEMPORALLY_CRIMINAL:
return new BLong( is_temporally_criminal() ? 1 : 0 );
break;
case MBR_IP:
if ( client != nullptr )
return new String( client->ipaddrAsString() );
return new String( "" );
break;
case MBR_GOLD:
return new BLong( gold_carried() );
break;
case MBR_TITLE_PREFIX:
return new String( title_prefix() );
break;
case MBR_TITLE_SUFFIX:
return new String( title_suffix() );
break;
case MBR_TITLE_GUILD:
return new String( title_guild() );
break;
case MBR_TITLE_RACE:
return new String( title_race() );
break;
case MBR_UCLANG:
return new String( uclang );
break;
case MBR_GUILDID:
return new BLong( guildid() );
break;
case MBR_GUILD:
if ( has_guild() )
return Module::GuildExecutorModule::CreateGuildRefObjImp( guild() );
return new BError( "Not a member of a guild" );
break;
case MBR_MURDERER:
return new BLong( is_murderer() ? 1 : 0 );
break;
case MBR_ATTACHED:
if ( script_ex == nullptr )
return new BError( "No script attached." );
return new Core::ScriptExObjImp( script_ex );
break;
case MBR_CLIENTVERSION:
if ( client != nullptr )
return new String( client->getversion() );
return new String( "" );
break;
case MBR_CLIENTVERSIONDETAIL:
if ( client != nullptr )
{
std::unique_ptr<BStruct> info( new BStruct );
Network::VersionDetailStruct version = client->getversiondetail();
info->addMember( "major", new BLong( version.major ) );
info->addMember( "minor", new BLong( version.minor ) );
info->addMember( "rev", new BLong( version.rev ) );
info->addMember( "patch", new BLong( version.patch ) );
return info.release();
}
else
{
std::unique_ptr<BStruct> info( new BStruct );
info->addMember( "major", new BLong( 0 ) );
info->addMember( "minor", new BLong( 0 ) );
info->addMember( "rev", new BLong( 0 ) );
info->addMember( "patch", new BLong( 0 ) );
return info.release();
}
break;
case MBR_CLIENTINFO:
if ( client != nullptr )
return client->getclientinfo();
return new BLong( 0 );
break;
case MBR_CREATEDAT:
return new BLong( created_at );
break;
case MBR_REPORTABLES:
return GetReportables();
break;
case MBR_OPPONENT:
if ( opponent_ != nullptr )
return opponent_->make_ref();
return new BError( "Mobile does not have any opponent selected." );
break;
case MBR_CONNECTED:
return new BLong( connected() ? 1 : 0 );
break;
case MBR_TRADING_WITH:
if ( trading_with != nullptr )
return trading_with->make_ref();
return new BError( "Mobile is not currently trading with anyone." );
break;
case MBR_CLIENTTYPE:
return new BLong( client != nullptr ? client->ClientType : 0 );
break;
case MBR_CURSOR:
if ( client != nullptr )
return new BLong( target_cursor_busy() ? 1 : 0 );
return new BLong( 0 );
break;
case MBR_GUMP:
if ( client != nullptr )
return new BLong( has_active_gump() ? 1 : 0 );
return new BLong( 0 );
break;
case MBR_PROMPT:
if ( client != nullptr )
return new BLong( has_active_prompt() ? 1 : 0 );
return new BLong( 0 );
break;
case MBR_MOVEMODE:
{
std::string mode = "";
if ( movemode & Plib::MOVEMODE_LAND )
mode = "L";
if ( movemode & Plib::MOVEMODE_SEA )
mode += "S";
if ( movemode & Plib::MOVEMODE_AIR )
mode += "A";
if ( movemode & Plib::MOVEMODE_FLY )
mode += "F";
return new String( mode );
break;
}
case MBR_HITCHANCE_MOD:
return new BLong( hitchance_mod() );
break;
case MBR_EVASIONCHANCE_MOD:
return new BLong( evasionchance_mod() );
break;
case MBR_CARRYINGCAPACITY_MOD:
return new BLong( carrying_capacity_mod() );
break;
case MBR_CARRYINGCAPACITY:
return new BLong( carrying_capacity() );
break;
case MBR_FIRE_RESIST:
return new BLong( EnforceCaps( fire_resist().sum(), fire_resist_cap().sum() ) );
case MBR_COLD_RESIST:
return new BLong( EnforceCaps( cold_resist().sum(), cold_resist_cap().sum() ) );
case MBR_ENERGY_RESIST:
return new BLong( EnforceCaps( energy_resist().sum(), energy_resist_cap().sum() ) );
case MBR_POISON_RESIST:
return new BLong( EnforceCaps( poison_resist().sum(), poison_resist_cap().sum() ) );
case MBR_PHYSICAL_RESIST:
return new BLong( EnforceCaps( physical_resist().sum(), physical_resist_cap().sum() ) );
case MBR_FIRE_RESIST_MOD:
return new BLong( fire_resist().mod );
break;
case MBR_COLD_RESIST_MOD:
return new BLong( cold_resist().mod );
break;
case MBR_ENERGY_RESIST_MOD:
return new BLong( energy_resist().mod );
break;
case MBR_POISON_RESIST_MOD:
return new BLong( poison_resist().mod );
break;
case MBR_PHYSICAL_RESIST_MOD:
return new BLong( physical_resist().mod );
break;
case MBR_FIRE_RESIST_CAP:
return new BLong( fire_resist_cap().sum() );
break;
case MBR_COLD_RESIST_CAP:
return new BLong( cold_resist_cap().sum() );
break;
case MBR_ENERGY_RESIST_CAP:
return new BLong( energy_resist_cap().sum() );
break;
case MBR_POISON_RESIST_CAP:
return new BLong( poison_resist_cap().sum() );
break;
case MBR_PHYSICAL_RESIST_CAP:
return new BLong( physical_resist_cap().sum() );
break;
case MBR_FIRE_RESIST_CAP_MOD:
return new BLong( fire_resist_cap().mod );
break;
case MBR_COLD_RESIST_CAP_MOD:
return new BLong( cold_resist_cap().mod );
break;
case MBR_ENERGY_RESIST_CAP_MOD:
return new BLong( energy_resist_cap().mod );
break;
case MBR_POISON_RESIST_CAP_MOD:
return new BLong( poison_resist_cap().mod );
break;
case MBR_PHYSICAL_RESIST_CAP_MOD:
return new BLong( physical_resist_cap().mod );
break;
case MBR_LOWER_REAG_COST:
return new BLong( lower_reagent_cost().sum() );
break;
case MBR_SPELL_DAMAGE_INCREASE:
return new BLong( spell_damage_increase().sum() );
break;
case MBR_FASTER_CASTING:
return new BLong( faster_casting().sum() );
break;
case MBR_FASTER_CAST_RECOVERY:
return new BLong( faster_cast_recovery().sum() );
break;
case MBR_LOWER_REAG_COST_MOD:
return new BLong( lower_reagent_cost().mod );
break;
case MBR_SPELL_DAMAGE_INCREASE_MOD:
return new BLong( spell_damage_increase().mod );
break;
case MBR_FASTER_CASTING_MOD:
return new BLong( faster_casting().mod );
break;
case MBR_FASTER_CAST_RECOVERY_MOD:
return new BLong( faster_cast_recovery().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_MOD:
return new BLong( defence_increase().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
return new BLong( defence_increase_cap().mod );
break;
case MBR_LOWER_MANA_COST_MOD:
return new BLong( lower_mana_cost().mod );
break;
case MBR_HIT_CHANCE_MOD:
return new BLong( hit_chance().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE:
return new BLong( EnforceCaps( defence_increase().sum(), defence_increase_cap().sum() ) );
break;
case MBR_DEFENCE_CHANCE_INCREASE_CAP:
return new BLong( defence_increase_cap().sum() );
break;
case MBR_LOWER_MANA_COST:
return new BLong( lower_mana_cost().sum() );
break;
case MBR_HIT_CHANCE:
return new BLong( hit_chance().sum() );
break;
case MBR_STATCAP:
return new BLong( skillstatcap().statcap );
break;
case MBR_SKILLCAP:
return new BLong( skillstatcap().skillcap );
break;
case MBR_LUCK:
return new BLong( luck().sum() );
break;
case MBR_LUCK_MOD:
return new BLong( luck().mod );
break;
case MBR_SWING_SPEED_INCREASE:
return new BLong( swing_speed_increase().sum() );
break;
case MBR_SWING_SPEED_INCREASE_MOD:
return new BLong( swing_speed_increase().mod );
break;
case MBR_FOLLOWERSMAX:
return new BLong( followers().followers_max );
break;
case MBR_TITHING:
return new BLong( tithing() );
break;
case MBR_FOLLOWERS:
return new BLong( followers().followers );
break;
case MBR_FIRE_DAMAGE:
return new BLong( fire_damage().sum() );
break;
case MBR_COLD_DAMAGE:
return new BLong( cold_damage().sum() );
break;
case MBR_ENERGY_DAMAGE:
return new BLong( energy_damage().sum() );
break;
case MBR_POISON_DAMAGE:
return new BLong( poison_damage().sum() );
break;
case MBR_PHYSICAL_DAMAGE:
return new BLong( physical_damage().sum() );
break;
case MBR_FIRE_DAMAGE_MOD:
return new BLong( fire_damage().mod );
break;
case MBR_COLD_DAMAGE_MOD:
return new BLong( cold_damage().mod );
break;
case MBR_ENERGY_DAMAGE_MOD:
return new BLong( energy_damage().mod );
break;
case MBR_POISON_DAMAGE_MOD:
return new BLong( poison_damage().mod );
break;
case MBR_PHYSICAL_DAMAGE_MOD:
return new BLong( physical_damage().mod );
break;
case MBR_PARTY:
if ( has_party() )
return Module::CreatePartyRefObjImp( party() );
return new BError( "Not a member of a party" );
break;
case MBR_PARTYLOOT:
return new BLong( party_can_loot() );
case MBR_CANDIDATE_OF_PARTY:
if ( has_candidate_of() )
return Module::CreatePartyRefObjImp( candidate_of() );
return new BError( "Not a candidate of a party" );
break;
case MBR_MOVECOST_WALK:
return new Double( movement_cost().walk );
break;
case MBR_MOVECOST_RUN:
return new Double( movement_cost().run );
break;
case MBR_MOVECOST_WALK_MOUNTED:
return new Double( movement_cost().walk_mounted );
break;
case MBR_MOVECOST_RUN_MOUNTED:
return new Double( movement_cost().run_mounted );
break;
case MBR_AGGRESSORTO:
return GetAggressorTo();
break;
case MBR_LAWFULLYDAMAGED:
return GetLawFullyDamaged();
break;
case MBR_UO_EXPANSION_CLIENT:
return new BLong( client != nullptr ? client->UOExpansionFlagClient : 0 );
break;
case MBR_DEAFENED:
return new BLong( deafened() ? 1 : 0 );
break;
case MBR_CLIENT:
if ( ( client != nullptr ) && ( client->isConnected() ) )
return client->make_ref();
return new BError( "No client attached." );
break;
case MBR_EDITING:
return new BLong( is_house_editing() ? 1 : 0 );
break;
case MBR_LASTCOORD:
if ( client != nullptr )
{
const Core::Pos3d last_pos = this->lastxyz;
std::unique_ptr<BStruct> lastcoord( new BStruct );
lastcoord->addMember( "lastx", new BLong( last_pos.x() ) );
lastcoord->addMember( "lasty", new BLong( last_pos.y() ) );
lastcoord->addMember( "lastz", new BLong( last_pos.z() ) );
return lastcoord.release();
}
return new BError( "No client attached." );
case MBR_ACTIVE_SKILL:
return new BLong( skill_ex_active() );
case MBR_CASTING_SPELL:
return new BLong( casting_spell() );
case MBR_LAST_TEXTCOLOR:
return new BLong( last_textcolor() );
}
// if all else fails, returns nullptr
return nullptr;
}
BObjectImp* Character::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* Character::set_script_member_id( const int id, const std::string& value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
String* ret;
switch ( id )
{
case MBR_TITLE_PREFIX:
title_prefix( value );
ret = new String( value );
break;
case MBR_TITLE_SUFFIX:
title_suffix( value );
ret = new String( value );
break;
case MBR_TITLE_GUILD:
title_guild( value );
ret = new String( value );
break;
case MBR_TITLE_RACE:
title_race( value );
ret = new String( value );
break;
default:
return nullptr;
}
set_dirty();
increv();
if ( this->has_active_client() )
send_object_cache_to_inrange( this );
return ret;
}
BObjectImp* Character::set_script_member( const char* membername, const std::string& value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* Character::set_script_member_id( const int id, int value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_GENDER:
if ( value )
gender = Plib::GENDER_FEMALE;
else
gender = Plib::GENDER_MALE;
return new BLong( gender );
case MBR_RACE:
if ( value == Plib::RACE_HUMAN )
race = Plib::RACE_HUMAN;
else if ( value == Plib::RACE_ELF )
race = Plib::RACE_ELF;
else if ( value == Plib::RACE_GARGOYLE )
race = Plib::RACE_GARGOYLE;
if ( ( race != Plib::RACE_GARGOYLE ) &&
( movemode & Plib::MOVEMODE_FLY ) ) // FIXME graphic based maybe?
movemode = ( Plib::MOVEMODE )( movemode ^ Plib::MOVEMODE_FLY ); // remove flying
return new BLong( race );
case MBR_TRUEOBJTYPE:
return new BLong( trueobjtype = static_cast<unsigned int>( value ) );
case MBR_TRUECOLOR:
return new BLong( truecolor = static_cast<unsigned short>( value ) );
case MBR_AR_MOD:
ar_mod( static_cast<short>( value ) );
refresh_ar();
return new BLong( ar_mod() );
case MBR_DELAY_MOD:
delay_mod( static_cast<short>( value ) );
return new BLong( delay_mod() );
case MBR_HIDDEN:
{
// FIXME: don't call on_change unless the value actually changed?
hidden( value ? true : false );
return new BLong( hidden() );
}
case MBR_CONCEALED:
concealed( static_cast<unsigned char>( value ) );
return new BLong( concealed() );
case MBR_FROZEN:
mob_flags_.change( MOB_FLAGS::FROZEN, value ? true : false );
return new BLong( frozen() );
case MBR_PARALYZED:
mob_flags_.change( MOB_FLAGS::PARALYZED, value ? true : false );
return new BLong( paralyzed() );
case MBR_POISONED:
poisoned( value ? true : false );
return new BLong( poisoned() );
case MBR_STEALTHSTEPS:
return new BLong( stealthsteps_ = static_cast<unsigned short>( value ) );
case MBR_MOUNTEDSTEPS:
return new BLong( mountedsteps_ = static_cast<unsigned int>( value ) );
case MBR_CMDLEVEL:
if ( value >= static_cast<int>( Core::gamestate.cmdlevels.size() ) )
cmdlevel( static_cast<unsigned char>( Core::gamestate.cmdlevels.size() ) - 1, true );
else
cmdlevel( static_cast<unsigned char>( value ), true );
return new BLong( cmdlevel() );
case MBR_MURDERER:
// make_murderer handles the updating
make_murderer( value ? true : false );
return new BLong( is_murderer() );
case MBR_HITCHANCE_MOD:
hitchance_mod( static_cast<short>( value ) );
return new BLong( hitchance_mod() );
case MBR_EVASIONCHANCE_MOD:
evasionchance_mod( static_cast<short>( value ) );
return new BLong( evasionchance_mod() );
case MBR_CARRYINGCAPACITY_MOD:
carrying_capacity_mod( static_cast<short>( value ) );
if ( client != nullptr )
{ // CHECKME consider sending less frequently
send_full_statmsg( client, this );
}
return new BLong( carrying_capacity_mod() );
case MBR_FACING:
if ( !face( static_cast<Core::UFACING>( value & PKTIN_02_FACING_MASK ), 0 ) )
return new BLong( 0 );
on_facing_changed();
return new BLong( 1 );
case MBR_FIRE_RESIST_MOD:
fire_resist( fire_resist().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( fire_resist().mod );
break;
case MBR_COLD_RESIST_MOD:
cold_resist( cold_resist().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( cold_resist().mod );
break;
case MBR_ENERGY_RESIST_MOD:
energy_resist( energy_resist().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( energy_resist().mod );
break;
case MBR_POISON_RESIST_MOD:
poison_resist( poison_resist().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( poison_resist().mod );
break;
case MBR_PHYSICAL_RESIST_MOD:
physical_resist( physical_resist().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( physical_resist().mod );
break;
case MBR_LOWER_REAG_COST_MOD:
lower_reagent_cost( lower_reagent_cost().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( lower_reagent_cost().mod );
break;
case MBR_SPELL_DAMAGE_INCREASE_MOD:
spell_damage_increase( spell_damage_increase().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( spell_damage_increase().mod );
break;
case MBR_FASTER_CASTING_MOD:
faster_casting( faster_casting().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( faster_casting().mod );
break;
case MBR_FASTER_CAST_RECOVERY_MOD:
faster_cast_recovery( faster_cast_recovery().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( faster_cast_recovery().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_MOD:
defence_increase( defence_increase().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( defence_increase().mod );
break;
case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
defence_increase_cap( defence_increase_cap().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( defence_increase_cap().mod );
break;
case MBR_LOWER_MANA_COST_MOD:
lower_mana_cost( lower_mana_cost().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( lower_mana_cost().mod );
break;
case MBR_HIT_CHANCE_MOD:
hit_chance( hit_chance().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( hit_chance().mod );
break;
case MBR_FIRE_RESIST_CAP_MOD:
fire_resist_cap( fire_resist_cap().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( fire_resist_cap().mod );
break;
case MBR_COLD_RESIST_CAP_MOD:
cold_resist_cap( cold_resist_cap().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( cold_resist_cap().mod );
break;
case MBR_ENERGY_RESIST_CAP_MOD:
energy_resist_cap( energy_resist_cap().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( energy_resist_cap().mod );
break;
case MBR_PHYSICAL_RESIST_CAP_MOD:
physical_resist_cap( physical_resist_cap().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( physical_resist_cap().mod );
break;
case MBR_POISON_RESIST_CAP_MOD:
poison_resist_cap( poison_resist_cap().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( poison_resist_cap().mod );
break;
case MBR_LUCK_MOD:
luck( luck().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( luck().mod );
break;
case MBR_SWING_SPEED_INCREASE_MOD:
swing_speed_increase( swing_speed_increase().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( swing_speed_increase().mod );
break;
case MBR_STATCAP:
{
auto val = skillstatcap();
val.statcap = static_cast<short>( value );
skillstatcap( val );
if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
on_aos_ext_stat_changed();
return new BLong( skillstatcap().statcap );
}
case MBR_SKILLCAP:
{
auto val = skillstatcap();
val.skillcap = static_cast<u16>( value );
skillstatcap( val );
return new BLong( skillstatcap().skillcap );
}
case MBR_FOLLOWERSMAX:
{
auto val = followers();
val.followers_max = static_cast<u8>( value );
followers( val );
if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
on_aos_ext_stat_changed();
return new BLong( followers().followers_max );
}
case MBR_TITHING:
tithing( static_cast<s32>( value ) );
if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
on_aos_ext_stat_changed();
return new BLong( tithing() );
break;
case MBR_FOLLOWERS:
{
auto val = followers();
val.followers = static_cast<u8>( value );
followers( val );
if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
on_aos_ext_stat_changed();
return new BLong( followers().followers );
}
case MBR_FIRE_DAMAGE_MOD:
fire_damage( fire_damage().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( fire_damage().mod );
break;
case MBR_COLD_DAMAGE_MOD:
cold_damage( cold_damage().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( cold_damage().mod );
break;
case MBR_ENERGY_DAMAGE_MOD:
energy_damage( energy_damage().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( energy_damage().mod );
break;
case MBR_POISON_DAMAGE_MOD:
poison_damage( poison_damage().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( poison_damage().mod );
break;
case MBR_PHYSICAL_DAMAGE_MOD:
physical_damage( physical_damage().setAsMod( static_cast<short>( value ) ) );
refresh_ar();
return new BLong( physical_damage().mod );
break;
case MBR_MOVECOST_WALK:
{
auto val = movement_cost();
val.walk = static_cast<double>( value );
movement_cost( val );
return new Double( movement_cost().walk );
}
case MBR_MOVECOST_RUN:
{
auto val = movement_cost();
val.run = static_cast<double>( value );
movement_cost( val );
return new Double( movement_cost().run );
}
case MBR_MOVECOST_WALK_MOUNTED:
{
auto val = movement_cost();
val.walk_mounted = static_cast<double>( value );
movement_cost( val );
return new Double( movement_cost().walk_mounted );
}
case MBR_MOVECOST_RUN_MOUNTED:
{
auto val = movement_cost();
val.run_mounted = static_cast<double>( value );
movement_cost( val );
return new Double( movement_cost().run_mounted );
}
default:
return nullptr;
}
}
BObjectImp* Character::set_script_member_id_double( const int id, double value )
{
switch ( id )
{
case MBR_MOVECOST_WALK:
{
auto val = movement_cost();
val.walk = value;
movement_cost( val );
return new Double( movement_cost().walk );
}
case MBR_MOVECOST_RUN:
{
auto val = movement_cost();
val.run = value;
movement_cost( val );
return new Double( movement_cost().run );
}
case MBR_MOVECOST_WALK_MOUNTED:
{
auto val = movement_cost();
val.walk_mounted = value;
movement_cost( val );
return new Double( movement_cost().walk_mounted );
}
case MBR_MOVECOST_RUN_MOUNTED:
{
auto val = movement_cost();
val.run_mounted = value;
movement_cost( val );
return new Double( movement_cost().run_mounted );
}
default:
return nullptr;
}
}
BObjectImp* Character::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* Character::script_method_id( const int id, Core::UOExecutor& ex )
{
BObjectImp* imp = base::script_method_id( id, ex );
if ( imp != nullptr )
return imp;
switch ( id )
{
/*
mobile.SetPoisoned( ispoisoned := 1 )
If the poisoned flag was changed, and the script has a controller
If poisoned was SET,
apply RepSystem rules (Mobile damages Mobile)
else poisoned was CLEARED, so
apply RepSystem rules (Mobile helps Mobile)
*/
case MTH_SETPOISONED:
{
bool newval = true;
if ( ex.hasParams( 1 ) )
{
int lval;
if ( !ex.getParam( 0, lval ) )
return new BError( "Invalid parameter type" );
if ( !lval )
newval = false;
}
if ( newval != poisoned() )
{
set_dirty();
poisoned( newval );
check_undamaged();
Module::UOExecutorModule* uoexec =
static_cast<Module::UOExecutorModule*>( ex.findModule( "UO" ) );
if ( uoexec != nullptr && uoexec->controller_.get() )
{
Character* attacker = uoexec->controller_.get();
if ( !attacker->orphan() )
{
if ( poisoned() )
attacker->repsys_on_damage( this );
else
attacker->repsys_on_help( this );
}
}
}
return new BLong( 1 );
}
/*
mobile.SetParalyzed( isparalyzed := 1 )
If the paralyzed flag was changed, and the script has a controller
if paralyzed was SET,
apply RepSystem rules (Mobile damages Mobile)
else paralyzed was CLEARED, so
apply RepSystem rules (Mobile heals Mobile)
*/
case MTH_SETPARALYZED:
{
bool newval = true;
if ( ex.hasParams( 1 ) )
{
int lval;
if ( !ex.getParam( 0, lval ) )
return new BError( "Invalid parameter type" );
if ( !lval )
newval = false;
}
if ( newval != paralyzed() )
{
set_dirty();
mob_flags_.change( MOB_FLAGS::PARALYZED, newval );
check_undamaged();
Module::UOExecutorModule* uoexec =
static_cast<Module::UOExecutorModule*>( ex.findModule( "UO" ) );
if ( uoexec != nullptr && uoexec->controller_.get() )
{
Character* attacker = uoexec->controller_.get();
if ( !attacker->orphan() )
{
if ( paralyzed() )
attacker->repsys_on_damage( this );
else
attacker->repsys_on_help( this );
}
}
}
return new BLong( 1 );
}
/*
mobile.SetCriminal( level := 1 )
if level is 0, clears the CriminalTimer
*/
case MTH_SETCRIMINAL:
{
int level = 1;
if ( ex.hasParams( 1 ) )
{
if ( !ex.getParam( 0, level ) )
return new BError( "Invalid parameter type" );
if ( level < 0 )
return new BError( "Level must be >= 0" );
}
set_dirty();
// make_criminal handles the updating
make_criminal( level );
return new BLong( 1 );
}
case MTH_SETLIGHTLEVEL:
{
int level, duration;
if ( !ex.hasParams( 2 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, level ) && ex.getParam( 1, duration ) )
{
lightoverride( level );
if ( duration == -1 )
lightoverride_until( ~0u );
else if ( duration == 0 )
lightoverride_until( 0 );
else
lightoverride_until( Core::read_gameclock() + duration );
check_region_changes();
if ( duration == -1 )
return new BLong( duration );
return new BLong( lightoverride_until() );
}
break;
}
case MTH_SETSEASON:
{
int season_id, playsound;
if ( !ex.hasParams( 2 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, season_id ) && ex.getParam( 1, playsound ) )
{
if ( season_id < 0 || season_id > 4 )
return new BError( "Invalid season id" );
if ( client && client->getversiondetail().major >= 1 )
{
Network::PktHelper::PacketOut<Network::PktOut_BC> msg;
msg->Write<u8>( static_cast<u16>( season_id ) );
msg->Write<u8>( static_cast<u16>( playsound ) );
msg.Send( client );
return new BLong( 1 );
}
}
break;
}
case MTH_SQUELCH:
{
int duration;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, duration ) )
{
set_dirty();
if ( duration == -1 )
{
squelched_until( ~0u );
return new BLong( -1 );
}
else if ( duration == 0 )
squelched_until( 0 );
else
squelched_until( Core::read_gameclock() + duration );
return new BLong( squelched_until() );
}
break;
}
case MTH_ENABLE:
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
const String* pstr;
if ( ex.getStringParam( 0, pstr ) )
{
if ( has_privilege( pstr->data() ) )
{
set_dirty();
set_setting( pstr->data(), true );
return new BLong( 1 );
}
return new BError( "Mobile doesn't have that privilege" );
}
break;
}
case MTH_DISABLE:
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
const String* pstr;
if ( ex.getStringParam( 0, pstr ) )
{
set_dirty();
set_setting( pstr->data(), false );
return new BLong( 1 );
}
break;
}
case MTH_ENABLED:
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
const String* pstr;
if ( ex.getStringParam( 0, pstr ) )
return new BLong( setting_enabled( pstr->data() ) ? 1 : 0 );
break;
}
case MTH_PRIVILEGES:
{
std::unique_ptr<BDictionary> dict( new BDictionary );
ISTRINGSTREAM istrm( all_privs() );
std::string tmp;
while ( istrm >> tmp )
{
dict->addMember( new String( tmp ), new BLong( setting_enabled( tmp.c_str() ) ) );
}
return dict.release();
break;
}
case MTH_SETCMDLEVEL:
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
const String* pstr;
if ( ex.getStringParam( 0, pstr ) )
{
Core::CmdLevel* pcmdlevel = Core::find_cmdlevel( pstr->data() );
if ( pcmdlevel )
{
set_dirty();
cmdlevel( pcmdlevel->cmdlevel, true );
return new BLong( 1 );
}
return new BError( "No such command level" );
}
break;
}
case MTH_SPENDGOLD:
{
int amt;
if ( ex.numParams() != 1 || !ex.getParam( 0, amt ) )
return new BError( "Invalid parameter type" );
if ( gold_carried() < static_cast<unsigned int>( amt ) )
return new BError( "Insufficient funds" );
spend_gold( amt );
return new BLong( 1 );
}
case MTH_SETMURDERER:
{
int lnewval = 1;
if ( ex.hasParams( 1 ) )
{
if ( !ex.getParam( 0, lnewval ) )
return new BError( "Invalid parameter type" );
}
set_dirty();
// make_murderer handles the updating
make_murderer( lnewval ? true : false );
return new BLong( 1 );
}
case MTH_REMOVEREPORTABLE:
{
if ( !ex.hasParams( 2 ) )
return new BError( "Not enough parameters" );
int repserial, gameclock;
if ( ex.getParam( 0, repserial ) && ex.getParam( 1, gameclock ) )
{
set_dirty();
clear_reportable( repserial, gameclock );
return new BLong( 1 );
}
break;
}
case MTH_GETGOTTENITEM:
if ( has_gotten_item() )
return new Module::EItemRefObjImp( gotten_item() );
return new BError( "Gotten Item nullptr" );
break;
case MTH_CLEARGOTTENITEM:
if ( has_gotten_item() )
{
clear_gotten_item();
return new BLong( 1 );
}
return new BError( "No Gotten Item" );
break;
case MTH_SETWARMODE:
{
int newmode;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, newmode, 0, 1 ) )
{
set_warmode( ( newmode == 0 ) ? false : true );
// FIXME: Additional checks needed?
if ( client )
send_warmode();
return new BLong( warmode() );
}
break;
}
case MTH_GETCORPSE:
{
Core::UCorpse* corpse_obj =
static_cast<Core::UCorpse*>( Core::system_find_item( last_corpse ) );
if ( corpse_obj != nullptr && !corpse_obj->orphan() )
return new Module::EItemRefObjImp( corpse_obj );
return new BError( "No corpse was found." );
break;
}
case MTH_SET_SWINGTIMER:
{
int time;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, time ) )
{
if ( time < 0 )
return new BError( "Time must be >= 0" );
Core::polclock_t clocks;
clocks = ( time * Core::POLCLOCKS_PER_SEC ) / 1000;
return new BLong( manual_set_swing_timer( clocks ) ? 1 : 0 );
}
break;
}
case MTH_ATTACK_ONCE:
{
Character* chr;
if ( ex.hasParams( 1 ) )
{
if ( ex.getCharacterParam( 0, chr ) )
{
if ( dead() )
return new BError( "Character is dead" );
if ( is_attackable( chr ) )
attack( chr );
else
return new BError( "Opponent is not attackable" );
}
else
return new BError( "Invalid parameter type" );
}
else
{
chr = get_attackable_opponent();
if ( chr != nullptr )
{
if ( !dead() )
attack( chr );
else
return new BError( "Character is dead" );
}
else
return new BError( "No opponent" );
}
return new BLong( 1 );
break;
}
case MTH_KILL:
if ( ex.hasParams( 1 ) )
{
Character* chr;
if ( ex.getCharacterParam( 0, chr ) )
chr->repsys_on_damage( this );
}
if ( dead() )
return new BError( "That is already dead!" );
die();
return new BLong( 1 );
break;
case MTH_SETFACING:
{
int flags = 0;
Core::UFACING i_facing;
if ( ex.hasParams( 2 ) && !ex.getParam( 1, flags, 0, 1 ) )
return new BError( "Invalid flags for parameter 1" );
BObjectImp* param0 = ex.getParamImp( 0 );
if ( param0->isa( BObjectImp::OTString ) )
{
const char* szDir = ex.paramAsString( 0 );
if ( DecodeFacing( szDir, i_facing ) == false )
return new BError( "Invalid string for parameter 0" );
}
else if ( param0->isa( BObjectImp::OTLong ) )
{
BLong* blong = static_cast<BLong*>( param0 );
i_facing = static_cast<Core::UFACING>( blong->value() & PKTIN_02_FACING_MASK );
}
else
return new BError( "Invalid type for parameter 0" );
if ( !face( i_facing, flags ) )
return new BLong( 0 );
on_facing_changed();
return new BLong( 1 );
break;
}
case MTH_COMPAREVERSION:
if ( client != nullptr )
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
const String* pstr;
if ( ex.getStringParam( 0, pstr ) )
return new BLong( client->compareVersion( pstr->getStringRep() ) ? 1 : 0 );
return new BError( "Invalid parameter type" );
}
return new BError( "No client attached" );
break;
case MTH_SETAGGRESSORTO:
if ( ex.hasParams( 1 ) )
{
Character* chr;
if ( ex.getCharacterParam( 0, chr ) )
{
// make_aggressor_to handles the updating
this->make_aggressor_to( chr );
return new BLong( 1 );
}
return new BError( "Invalid parameter type" );
}
return new BError( "Not enough parameters" );
break;
case MTH_SETLAWFULLYDAMAGEDTO:
if ( ex.hasParams( 1 ) )
{
Character* chr;
if ( ex.getCharacterParam( 0, chr ) )
{
// make_lawfullydamaged_to handled the updating
this->make_lawfullydamaged_to( chr );
return new BLong( 1 );
}
return new BError( "Invalid parameter type" );
}
return new BError( "Not enough parameters" );
break;
case MTH_CLEARAGGRESSORTO:
if ( ex.hasParams( 1 ) )
{
Character* chr;
if ( ex.getCharacterParam( 0, chr ) )
{
this->remove_as_aggressor_to( chr );
return new BLong( 1 );
}
return new BError( "Invalid parameter type" );
}
return new BError( "Not enough parameters" );
break;
case MTH_CLEARLAWFULLYDAMAGEDTO:
if ( ex.hasParams( 1 ) )
{
Character* chr;
if ( ex.getCharacterParam( 0, chr ) )
{
this->remove_as_lawful_damager( chr );
return new BLong( 1 );
}
return new BError( "Invalid parameter type" );
}
return new BError( "Not enough parameters" );
break;
case MTH_DEAF:
{
int duration;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, duration ) )
{
set_dirty();
if ( duration == -1 )
{
deafened_until( ~0u );
return new BLong( -1 );
}
else if ( duration == 0 )
deafened_until( 0 );
else
deafened_until( Core::read_gameclock() + duration );
return new BLong( deafened_until() );
}
break;
}
case MTH_DISABLE_SKILLS_FOR:
{
int duration;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, duration ) )
{
if ( duration < 0 )
return new BError( "Duration must be >= 0" );
disable_skills_until( Core::poltime() + duration );
return new BLong( static_cast<int>( disable_skills_until() ) );
}
break;
}
case MTH_ADD_BUFF:
{
u16 icon;
u16 duration;
u32 cl_name;
u32 cl_descr;
const String* text;
if ( !ex.hasParams( 5 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, icon ) && ex.getParam( 1, duration ) && ex.getParam( 2, cl_name ) &&
ex.getParam( 3, cl_descr ) && ex.getUnicodeStringParam( 4, text ) )
{
if ( !( icon && cl_name && cl_descr ) )
return new BError( "Invalid parameters" );
if ( text->length() > SPEECH_MAX_LEN )
return new BError( "Text exceeds maximum size." );
addBuff( icon, duration, cl_name, cl_descr, text->value() );
return new BLong( 1 );
}
break;
}
case MTH_CLEAR_BUFFS:
{
clearBuffs();
return new BLong( 1 );
break;
}
case MTH_DEL_BUFF:
{
u16 icon;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, icon ) )
{
if ( !icon )
return new BError( "Invalid parameter" );
if ( !delBuff( icon ) )
return new BError( "Buff not found" );
return new BLong( 1 );
}
break;
}
default:
return nullptr;
}
return new BError( "Invalid parameter type" );
}
BObjectImp* Character::script_method( const char* methodname, Core::UOExecutor& ex )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, ex );
return nullptr;
}
BObjectImp* Character::custom_script_method( const char* methodname, Core::UOExecutor& ex )
{
// TODO uoclient entry deprecated
if ( Core::networkManager.uoclient_general.method_script != nullptr )
{
unsigned PC;
if ( Core::networkManager.uoclient_general.method_script->FindExportedFunction(
methodname, static_cast<unsigned int>( ex.numParams() + 1 ), PC ) )
return Core::networkManager.uoclient_general.method_script->call( PC, make_ref(),
ex.fparams );
}
return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
}
ObjArray* Character::GetReportables() const
{
std::unique_ptr<ObjArray> arr( new ObjArray );
for ( ReportableList::const_iterator itr = reportable_.begin(), end = reportable_.end();
itr != end; ++itr )
{
const reportable_t& rt = ( *itr );
std::unique_ptr<BObjectImp> kmember( nullptr );
Character* killer = Core::system_find_mobile( rt.serial );
if ( killer )
kmember.reset( new Module::EOfflineCharacterRefObjImp( killer ) );
else
kmember.reset( new BError( "Mobile not found" ) );
std::unique_ptr<BStruct> elem( new BStruct );
elem->addMember( "serial", new BLong( rt.serial ) );
elem->addMember( "killer", kmember.release() );
elem->addMember( "gameclock", new BLong( rt.polclock ) );
arr->addElement( elem.release() );
}
return arr.release();
}
ObjArray* Character::GetAggressorTo() const
{
std::unique_ptr<ObjArray> arr( new ObjArray );
for ( Character::MobileCont::const_iterator itr = aggressor_to_.begin(),
end = aggressor_to_.end();
itr != end; ++itr )
{
std::unique_ptr<BObjectImp> member( nullptr );
Character* chr = Core::system_find_mobile( ( *itr ).first->serial );
if ( chr )
member.reset( new Module::EOfflineCharacterRefObjImp( chr ) );
else
member.reset( new BError( "Mobile not found" ) );
std::unique_ptr<BStruct> elem( new BStruct );
elem->addMember( "serial", new BLong( ( *itr ).first->serial ) );
elem->addMember( "ref", member.release() );
elem->addMember(
"seconds", new BLong( ( ( *itr ).second - Core::polclock() ) / Core::POLCLOCKS_PER_SEC ) );
arr->addElement( elem.release() );
}
return arr.release();
}
ObjArray* Character::GetLawFullyDamaged() const
{
std::unique_ptr<ObjArray> arr( new ObjArray );
for ( Character::MobileCont::const_iterator itr = lawfully_damaged_.begin(),
end = lawfully_damaged_.end();
itr != end; ++itr )
{
std::unique_ptr<BObjectImp> member( nullptr );
Character* chr = Core::system_find_mobile( ( *itr ).first->serial );
if ( chr )
member.reset( new Module::EOfflineCharacterRefObjImp( chr ) );
else
member.reset( new BError( "Mobile not found" ) );
std::unique_ptr<BStruct> elem( new BStruct );
elem->addMember( "serial", new BLong( ( *itr ).first->serial ) );
elem->addMember( "ref", member.release() );
elem->addMember(
"seconds", new BLong( ( ( *itr ).second - Core::polclock() ) / Core::POLCLOCKS_PER_SEC ) );
arr->addElement( elem.release() );
}
return arr.release();
}
BObjectImp* NPC::get_script_member_id( const int id ) const
{
BObjectImp* imp = base::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_SCRIPT:
return new String( script );
break;
case MBR_NPCTEMPLATE:
return new String( template_name );
break;
case MBR_MASTER:
{
Character* master = master_.get();
if ( master != nullptr && !master->orphan() )
return new Module::EOfflineCharacterRefObjImp( master );
return new BLong( 0 );
break;
}
case MBR_PROCESS:
if ( ex )
return new Core::ScriptExObjImp( ex );
return new BError( "No script running" );
break;
case MBR_EVENTMASK:
if ( ex )
return new BLong( ex->eventmask );
return new BError( "No script running" );
break;
case MBR_SPEECH_COLOR:
return new BLong( speech_color() );
break;
case MBR_SPEECH_FONT:
return new BLong( speech_font() );
break;
case MBR_USE_ADJUSTMENTS:
return new BLong( use_adjustments() ? 1 : 0 );
break;
case MBR_RUN_SPEED:
return new BLong( run_speed );
break;
case MBR_ALIGNMENT:
return new BLong( this->template_.alignment );
break;
case MBR_SAVEONEXIT:
return new BLong( saveonexit() );
break;
case MBR_NO_DROP_EXCEPTION:
return new BLong( no_drop_exception() );
default:
return nullptr;
}
}
BObjectImp* NPC::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* NPC::set_script_member_id( const int id, const std::string& value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_SCRIPT:
return new String( script = value );
default:
return nullptr;
}
}
BObjectImp* NPC::set_script_member( const char* membername, const std::string& value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* NPC::set_script_member_id( const int id, int value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_SPEECH_COLOR:
speech_color( static_cast<unsigned short>( value ) );
return new BLong( speech_color() );
case MBR_SPEECH_FONT:
speech_font( static_cast<unsigned short>( value ) );
return new BLong( speech_font() );
case MBR_USE_ADJUSTMENTS:
use_adjustments( value ? true : false );
return new BLong( use_adjustments() );
case MBR_RUN_SPEED:
return new BLong( run_speed = static_cast<unsigned short>( value ) );
case MBR_SAVEONEXIT:
saveonexit( value ? true : false );
return new BLong( saveonexit() );
case MBR_NO_DROP_EXCEPTION:
no_drop_exception( value ? true : false );
return new BLong( no_drop_exception() );
default:
return nullptr;
}
}
BObjectImp* NPC::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* NPC::script_method_id( const int id, Core::UOExecutor& executor )
{
BObjectImp* imp = base::script_method_id( id, executor );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MTH_SETMASTER:
{
if ( executor.numParams() != 1 )
return new BError( "Not enough parameters" );
Character* chr;
set_dirty();
if ( executor.getCharacterParam( 0, chr ) )
{
master_.set( chr );
return new BLong( 1 );
}
else
{
master_.clear();
return new BLong( 0 );
}
break;
}
default:
return nullptr;
}
}
BObjectImp* NPC::script_method( const char* methodname, Core::UOExecutor& executor )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, executor );
return nullptr;
}
BObjectImp* NPC::custom_script_method( const char* methodname, Core::UOExecutor& executor )
{
if ( template_.method_script != nullptr )
{
unsigned PC;
if ( template_.method_script->FindExportedFunction(
methodname, static_cast<unsigned int>( executor.numParams() + 1 ), PC ) )
return template_.method_script->call( PC, make_ref(), executor.fparams );
}
return Core::gamestate.system_hooks.call_script_method( methodname, &executor, this );
}
} // namespace Mobile
namespace Core
{
using namespace Bscript;
BObjectImp* ULockable::get_script_member_id( const int id ) const
{
BObjectImp* imp = Item::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_LOCKED:
return new BLong( locked() ? 1 : 0 );
break;
default:
return nullptr;
}
}
BObjectImp* ULockable::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* ULockable::set_script_member_id( const int id, int value )
{
BObjectImp* imp = Item::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_LOCKED:
locked( value ? true : false );
return new BLong( locked() );
default:
return nullptr;
}
}
BObjectImp* ULockable::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UContainer::get_script_member_id( const int id ) const
{
BObjectImp* imp = base::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_MAX_ITEMS_MOD:
return new BLong( max_items_mod() );
break;
case MBR_MAX_WEIGHT_MOD:
return new BLong( max_weight_mod() );
break;
case MBR_MAX_SLOTS_MOD:
return new BLong( max_slots_mod() );
break;
case MBR_NO_DROP_EXCEPTION:
return new BLong( no_drop_exception() );
default:
return nullptr;
}
}
BObjectImp* UContainer::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* UContainer::set_script_member_id( const int id, int value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_MAX_ITEMS_MOD:
max_items_mod( static_cast<s16>( value ) );
break;
case MBR_MAX_WEIGHT_MOD:
max_weight_mod( static_cast<s16>( value ) );
break;
case MBR_MAX_SLOTS_MOD:
max_slots_mod( static_cast<s8>( value ) );
break;
case MBR_NO_DROP_EXCEPTION:
no_drop_exception( value ? true : false );
return new BLong( no_drop_exception() );
default:
return nullptr;
}
return new BLong( value );
}
BObjectImp* UContainer::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UCorpse::get_script_member_id( const int id ) const
{
BObjectImp* imp = base::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_CORPSETYPE:
return new BLong( corpsetype );
break;
case MBR_OWNERSERIAL:
return new BLong( ownerserial );
break;
default:
return nullptr;
}
}
BObjectImp* UCorpse::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* Spellbook::script_method_id( const int id, Core::UOExecutor& ex )
{
BObjectImp* imp = base::script_method_id( id, ex );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MTH_HASSPELL:
{
int sid;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, sid ) )
{
if ( sid <= 0 )
return new BError( "SpellID must be >= 1" );
if ( this->has_spellid( static_cast<unsigned int>( sid ) ) )
return new BLong( 1 );
else
return new BLong( 0 );
}
break;
}
case MTH_SPELLS:
{
std::unique_ptr<ObjArray> arr( new ObjArray );
for ( u16 i = 0; i < 64; ++i )
{
unsigned int sid;
// Check for Mysticism spells here
if ( this->spell_school == 3 )
sid = 678 + i;
else
sid = this->spell_school * 100 + i + 1;
if ( this->has_spellid( sid ) )
arr->addElement( new BLong( sid ) );
}
return arr.release();
break;
}
case MTH_REMOVESPELL:
{
int sid;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, sid ) )
{
if ( sid <= 0 )
return new BError( "SpellID must be >= 1" );
if ( this->remove_spellid( static_cast<unsigned int>( sid ) ) )
return new BLong( 1 );
else
return new BLong( 0 );
}
break;
}
case MTH_ADDSPELL:
{
int sid;
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
if ( ex.getParam( 0, sid ) )
{
if ( sid <= 0 )
return new BError( "SpellID must be >= 1" );
if ( this->add_spellid( static_cast<unsigned int>( sid ) ) )
return new BLong( 1 );
else
return new BLong( 0 );
}
break;
}
default:
return nullptr;
}
return new BError( "Invalid parameter type" );
}
BObjectImp* Spellbook::script_method( const char* methodname, Core::UOExecutor& ex )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, ex );
return nullptr;
}
} // namespace Core
namespace Multi
{
using namespace Bscript;
BObjectImp* UBoat::make_ref()
{
return new Module::EUBoatRefObjImp( this );
}
BObjectImp* UMulti::make_ref()
{
return new Module::EMultiRefObjImp( this );
}
BObjectImp* UBoat::get_script_member_id( const int id ) const
{
BObjectImp* imp = base::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_TILLERMAN:
{
Item* cp = tillerman;
if ( cp != nullptr )
return new Module::EItemRefObjImp( cp );
return new BError( std::string( "This ship doesn't have that component" ) );
break;
}
case MBR_PORTPLANK:
{
Item* cp = portplank;
if ( cp != nullptr )
return new Module::EItemRefObjImp( cp );
return new BError( std::string( "This ship doesn't have that component" ) );
break;
}
case MBR_STARBOARDPLANK:
{
Item* cp = starboardplank;
if ( cp != nullptr )
return new Module::EItemRefObjImp( cp );
return new BError( std::string( "This ship doesn't have that component" ) );
break;
}
case MBR_HOLD:
{
Item* cp = hold;
if ( cp != nullptr )
return new Module::EItemRefObjImp( cp );
return new BError( std::string( "This ship doesn't have that component" ) );
break;
}
case MBR_ROPE:
return component_list( COMPONENT_ROPE );
break;
case MBR_WHEEL:
return component_list( COMPONENT_WHEEL );
break;
case MBR_HULL:
return component_list( COMPONENT_HULL );
break;
case MBR_TILLER:
return component_list( COMPONENT_TILLER );
break;
case MBR_RUDDER:
return component_list( COMPONENT_RUDDER );
break;
case MBR_SAILS:
return component_list( COMPONENT_SAILS );
break;
case MBR_STORAGE:
return component_list( COMPONENT_STORAGE );
break;
case MBR_WEAPONSLOT:
return component_list( COMPONENT_WEAPONSLOT );
break;
case MBR_COMPONENTS:
return component_list( COMPONENT_ALL );
break;
case MBR_ITEMS:
return items_list();
break;
case MBR_MOBILES:
return mobiles_list();
break;
case MBR_HAS_OFFLINE_MOBILES:
return new BLong( has_offline_mobiles() ? 1 : 0 );
break;
case MBR_MULTIID:
return new BLong( multiid );
break;
default:
return nullptr;
}
}
BObjectImp* UBoat::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* UBoat::script_method_id( const int id, Core::UOExecutor& ex )
{
BObjectImp* imp = base::script_method_id( id, ex );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MTH_MOVE_OFFLINE_MOBILES:
{
if ( ex.numParams() == 3 )
{
Core::Pos3d newpos_xyz;
if ( ex.getPos3dParam( 0, 1, 2, &newpos_xyz, realm() ) )
{
set_dirty();
move_offline_mobiles( Core::Pos4d( newpos_xyz, realm() ) );
return new BLong( 1 );
}
else
return new BError( "Invalid parameter type" );
}
else if ( ex.numParams() == 4 )
{
Core::Pos4d newpos;
if ( ex.getPos4dParam( 0, 1, 2, 3, &newpos ) )
{
set_dirty();
move_offline_mobiles( newpos );
return new BLong( 1 );
}
else
return new BError( "Invalid parameter type" );
}
else
return new BError( "Not enough parameters" );
break;
}
default:
return nullptr;
}
}
BObjectImp* UBoat::script_method( const char* methodname, Core::UOExecutor& ex )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, ex );
return nullptr;
}
BObjectImp* UPlank::get_script_member_id( const int id ) const
{
switch ( id )
{
case MBR_MULTI:
if ( boat_.get() )
return new Module::EUBoatRefObjImp( boat_.get() );
return new BError( "No boat attached" );
break;
}
return base::get_script_member_id( id );
}
/* UObject defines a 'multi' also, so we have to trap that here first */
BObjectImp* UPlank::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return base::get_script_member( membername );
}
} // namespace Multi
namespace Core
{
using namespace Bscript;
BObjectImp* Map::get_script_member_id( const int id ) const
{
BObjectImp* imp = base::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_XEAST:
return new BLong( area.se().x() );
break;
case MBR_XWEST:
return new BLong( area.nw().x() );
break;
case MBR_YNORTH:
return new BLong( area.nw().y() );
break;
case MBR_YSOUTH:
return new BLong( area.se().y() );
break;
case MBR_GUMPWIDTH:
return new BLong( gumpwidth );
break;
case MBR_GUMPHEIGHT:
return new BLong( gumpheight );
break;
case MBR_FACETID:
return new BLong( facetid );
break;
case MBR_EDITABLE:
return new BLong( editable ? 1 : 0 );
break;
default:
return nullptr;
}
}
BObjectImp* Map::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* Map::set_script_member_id( const int id, int value )
{
BObjectImp* imp = base::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_XEAST:
area.se( Pos2d( area.se() ).x( static_cast<unsigned short>( value ) ) );
return new BLong( area.se().x() );
case MBR_XWEST:
area.nw( Pos2d( area.nw() ).x( static_cast<unsigned short>( value ) ) );
return new BLong( area.nw().x() );
case MBR_YNORTH:
area.nw( Pos2d( area.nw() ).y( static_cast<unsigned short>( value ) ) );
return new BLong( area.nw().y() );
case MBR_YSOUTH:
area.se( Pos2d( area.se() ).y( static_cast<unsigned short>( value ) ) );
return new BLong( area.se().y() );
case MBR_GUMPWIDTH:
return new BLong( gumpwidth = static_cast<unsigned short>( value ) );
case MBR_GUMPHEIGHT:
return new BLong( gumpheight = static_cast<unsigned short>( value ) );
case MBR_FACETID:
return new BLong( facetid = static_cast<unsigned short>( value ) );
case MBR_EDITABLE:
return new BLong( editable = value ? true : false );
default:
return nullptr;
}
}
BObjectImp* Map::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UObject::script_method_id( const int id, Core::UOExecutor& ex )
{
switch ( id )
{
case MTH_ISA:
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
int isatype;
if ( ex.getParam( 0, isatype ) )
return new BLong( script_isa( static_cast<unsigned>( isatype ) ) );
break;
}
case MTH_SET_MEMBER:
{
if ( !ex.hasParams( 2 ) )
return new BError( "Not enough parameters" );
BObjectImp* objimp;
const String* mname;
if ( ex.getStringParam( 0, mname ) && ( objimp = ex.getParamImp( 1 ) ) != nullptr )
{
BObjectImp* ret;
if ( objimp->isa( BObjectImp::OTLong ) )
{
BLong* lng = static_cast<BLong*>( objimp );
ret = set_script_member( mname->value().c_str(), lng->value() );
}
else if ( objimp->isa( BObjectImp::OTDouble ) )
{
Double* dbl = static_cast<Double*>( objimp );
ret = set_script_member_double( mname->value().c_str(), dbl->value() );
}
else if ( objimp->isa( BObjectImp::OTString ) )
{
String* str = static_cast<String*>( objimp );
ret = set_script_member( mname->value().c_str(), str->value() );
}
else
return new BError( "Invalid value type" );
if ( ret != nullptr )
return ret;
else
{
std::string message = std::string( "Member " ) + std::string( mname->value() ) +
std::string( " not found on that object" );
return new BError( message );
}
}
break;
}
case MTH_GET_MEMBER:
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
const String* mname;
if ( ex.getStringParam( 0, mname ) )
{
BObjectImp* ret = get_script_member( mname->value().c_str() );
if ( ret != nullptr )
return ret;
else
{
std::string message = std::string( "Member " ) + std::string( mname->value() ) +
std::string( " not found on that object" );
return new BError( message );
}
}
break;
}
default:
{
bool changed = false;
BObjectImp* imp = CallPropertyListMethod_id( proplist_, id, ex, changed );
if ( changed )
set_dirty();
return imp;
}
}
return new BError( "Invalid parameter type" );
}
BObjectImp* UObject::script_method( const char* methodname, Core::UOExecutor& ex )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, ex );
else
{
bool changed = false;
BObjectImp* imp = CallPropertyListMethod( proplist_, methodname, ex, changed );
if ( changed )
set_dirty();
return imp;
}
}
BObjectImp* UObject::custom_script_method( const char* methodname, Core::UOExecutor& ex )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, ex );
return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
}
BObjectImp* UDoor::get_script_member_id( const int id ) const
{
BObjectImp* imp = ULockable::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_ISOPEN:
return new BLong( is_open() ? 1 : 0 );
break;
default:
return nullptr;
}
}
BObjectImp* UDoor::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* UDoor::script_method_id( const int id, Core::UOExecutor& ex )
{
BObjectImp* imp = base::script_method_id( id, ex );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MTH_OPEN:
open();
break;
case MTH_CLOSE:
close();
break;
case MTH_TOGGLE:
toggle();
break;
default:
return nullptr;
}
return new BLong( 1 );
}
BObjectImp* UDoor::script_method( const char* methodname, Core::UOExecutor& ex )
{
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->script_method_id( objmethod->id, ex );
return nullptr;
}
} // namespace Core
namespace Items
{
using namespace Bscript;
BObjectImp* Equipment::get_script_member_id( const int id ) const
{
BObjectImp* imp = Item::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_INTRINSIC:
return new BLong( is_intrinsic() );
break;
default:
return nullptr;
}
}
BObjectImp* Equipment::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* Equipment::set_script_member_id( const int id, int value )
{
BObjectImp* imp = Item::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
return nullptr;
/*
switch(id)
{
default: return nullptr;
}
*/
}
BObjectImp* Equipment::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* Equipment::set_script_member_id_double( const int id, double value )
{
BObjectImp* imp = Item::set_script_member_id_double( id, value );
if ( imp != nullptr )
return imp;
return nullptr;
/*
switch(id)
{
default: return nullptr;
}
*/
}
BObjectImp* Equipment::set_script_member_double( const char* membername, double value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id_double( objmember->id, value );
return nullptr;
}
BObjectImp* UWeapon::get_script_member_id( const int id ) const
{
BObjectImp* imp = Equipment::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_DMG_MOD:
return new BLong( damage_mod() );
break;
case MBR_SPEED_MOD:
return new BLong( speed_mod() );
break;
case MBR_ATTRIBUTE:
return new String( attribute().name );
break;
case MBR_HITSCRIPT:
return new String( hit_script_.qualifiedname() );
break;
default:
return nullptr;
}
}
BObjectImp* UWeapon::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* UWeapon::set_script_member_id( const int id, const std::string& value )
{
BObjectImp* imp = Item::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_HITSCRIPT:
set_hit_script( value );
return new BLong( 1 );
default:
return nullptr;
}
}
BObjectImp* UWeapon::set_script_member( const char* membername, const std::string& value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UWeapon::set_script_member_id( const int id, int value )
{
if ( is_intrinsic() )
return new BError( "Cannot alter an instrinsic NPC weapon member values" ); // executor won't
// return this to
// the script
// currently.
BObjectImp* imp = Equipment::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_DMG_MOD:
damage_mod( static_cast<s16>( value ) );
break;
case MBR_SPEED_MOD:
speed_mod( static_cast<s16>( value ) );
break;
default:
return nullptr;
}
return new BLong( value );
}
BObjectImp* UWeapon::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UWeapon::set_script_member_id_double( const int id, double value )
{
if ( is_intrinsic() )
return new BError( "Cannot alter an instrinsic NPC weapon member values" ); // executor won't
// return this to
// the script
// currently.
return base::set_script_member_id_double( id, value );
}
BObjectImp* UWeapon::set_script_member_double( const char* membername, double value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id_double( objmember->id, value );
return base::set_script_member_double( membername, value );
}
BObjectImp* UArmor::get_script_member_id( const int id ) const
{
BObjectImp* imp = Equipment::get_script_member_id( id );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_AR_MOD:
return new BLong( ar_mod() );
break;
case MBR_AR:
return new BLong( ar() );
break;
case MBR_AR_BASE:
return new BLong( ar_base() );
break;
case MBR_ONHIT_SCRIPT:
// bad method name? nullptr makes it return the fullpath
return new String( onhitscript_.qualifiedname() );
break;
default:
return nullptr;
}
}
BObjectImp* UArmor::get_script_member( const char* membername ) const
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_script_member_id( objmember->id );
return nullptr;
}
BObjectImp* UArmor::set_script_member_id( const int id, const std::string& value )
{
BObjectImp* imp = Item::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_ONHIT_SCRIPT:
set_onhitscript( value );
return new BLong( 1 );
default:
return nullptr;
}
}
BObjectImp* UArmor::set_script_member( const char* membername, const std::string& value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
BObjectImp* UArmor::set_script_member_id( const int id, int value )
{
BObjectImp* imp = Equipment::set_script_member_id( id, value );
if ( imp != nullptr )
return imp;
switch ( id )
{
case MBR_AR_MOD:
this->ar_mod( static_cast<s16>( value ) );
if ( container != nullptr )
{
if ( Core::IsCharacter( container->serial ) )
{
Mobile::Character* chr = container->toplevel_chr();
if ( chr != nullptr )
Mobile::ARUpdater::on_change( chr );
}
}
return new BLong( value );
default:
return nullptr;
}
}
BObjectImp* UArmor::set_script_member( const char* membername, int value )
{
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_script_member_id( objmember->id, value );
return nullptr;
}
} // namespace Items
namespace Module
{
using namespace Bscript;
const char* EClientRefObjImp::typeOf() const
{
return "ClientRef";
}
u8 EClientRefObjImp::typeOfInt() const
{
return OTClientRef;
}
BObjectImp* EClientRefObjImp::copy() const
{
if ( value().exists() )
return value()->make_ref();
return new BError( "Client is disconnected" );
}
bool EClientRefObjImp::isTrue() const
{
return ( value().exists() && value()->isConnected() );
}
bool EClientRefObjImp::operator==( const BObjectImp& objimp ) const
{
if ( objimp.isa( BObjectImp::OTApplicObj ) )
{
const BApplicObjBase* aob =
Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
if ( aob->object_type() == &eclientrefobjimp_type )
{
const EClientRefObjImp* clientref_imp =
Clib::explicit_cast<const EClientRefObjImp*, const BApplicObjBase*>( aob );
if ( clientref_imp->value().exists() && value().exists() &&
( clientref_imp->value()->chr != nullptr ) && ( value()->chr != nullptr ) )
return ( clientref_imp->value()->chr->serial == value()->chr->serial );
return false;
}
return false;
}
else if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
return false;
}
BObjectRef EClientRefObjImp::get_member_id( const int id )
{
if ( ( !obj_.exists() ) || ( !obj_->isConnected() ) )
return BObjectRef( new BError( "Client not ready or disconnected" ) );
switch ( id )
{
case MBR_ACCTNAME:
if ( obj_->acct != nullptr )
return BObjectRef( new String( obj_->acct->name() ) );
return BObjectRef( new BError( "Not attached to an account" ) );
break;
case MBR_IP:
return BObjectRef( new String( obj_->ipaddrAsString() ) );
break;
case MBR_CLIENTVERSION:
return BObjectRef( new String( obj_->getversion() ) );
break;
case MBR_CLIENTVERSIONDETAIL:
{
std::unique_ptr<BStruct> info( new BStruct );
Network::VersionDetailStruct version = obj_->getversiondetail();
info->addMember( "major", new BLong( version.major ) );
info->addMember( "minor", new BLong( version.minor ) );
info->addMember( "rev", new BLong( version.rev ) );
info->addMember( "patch", new BLong( version.patch ) );
return BObjectRef( info.release() );
}
break;
case MBR_CLIENTINFO:
return BObjectRef( obj_->getclientinfo() );
break;
case MBR_CLIENTTYPE:
return BObjectRef( new BLong( obj_->ClientType ) );
break;
case MBR_UO_EXPANSION_CLIENT:
return BObjectRef( new BLong( obj_->UOExpansionFlagClient ) );
break;
case MBR_LAST_ACTIVITY_AT:
return BObjectRef( new BLong( obj_->last_activity_at ) );
break;
case MBR_LAST_PACKET_AT:
return BObjectRef( new BLong( obj_->last_packet_at ) );
break;
case MBR_PORT:
return BObjectRef( new BLong( obj_->listen_port ) );
break;
}
return base::get_member_id( id );
}
BObjectRef EClientRefObjImp::get_member( const char* membername )
{
if ( ( !obj_.exists() ) || ( !obj_->isConnected() ) )
return BObjectRef( new BError( "Client not ready or disconnected" ) );
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_member_id( objmember->id );
return BObjectRef( UninitObject::create() );
}
BObjectRef EClientRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
{
if ( !obj_.exists() || !obj_->isConnected() )
return BObjectRef( new BError( "Client not ready or disconnected" ) );
ObjMember* objmember = getKnownObjMember( membername );
if ( objmember != nullptr )
return this->set_member_id( objmember->id, value, copy );
return BObjectRef( UninitObject::create() );
}
BObjectRef EClientRefObjImp::set_member_id( const int /*id*/, BObjectImp* /*value*/, bool /*copy*/ )
{
if ( !obj_.exists() || !obj_->isConnected() )
return BObjectRef( new BError( "Client not ready or disconnected" ) );
return BObjectRef( UninitObject::create() );
}
BObjectImp* EClientRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
{
if ( !obj_.exists() || !obj_->isConnected() )
return new BError( "Client not ready or disconnected" );
bool forcebuiltin{Executor::builtinMethodForced( methodname )};
ObjMethod* objmethod = getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
}
BObjectImp* EClientRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
bool forcebuiltin )
{
if ( !obj_.exists() || !obj_->isConnected() )
return new BError( "Client not ready or disconnected" );
ObjMethod* mth = getObjMethod( id );
if ( mth->overridden && !forcebuiltin )
{
auto* imp = Core::gamestate.system_hooks.call_script_method( mth->code, &ex, this );
if ( imp )
return imp;
}
switch ( id )
{
case MTH_COMPAREVERSION:
{
if ( !ex.hasParams( 1 ) )
return new BError( "Not enough parameters" );
const String* pstr;
if ( ex.getStringParam( 0, pstr ) )
return new BLong( obj_->compareVersion( pstr->getStringRep() ) ? 1 : 0 );
return new BError( "Invalid parameter type" );
}
}
return base::call_polmethod_id( id, ex );
}
SourcedEvent::SourcedEvent( Core::EVENTID type, Mobile::Character* source )
{
addMember( "type", new BLong( type ) );
addMember( "source", new Module::EOfflineCharacterRefObjImp( source ) );
}
SpeechEvent::SpeechEvent( Mobile::Character* speaker, const std::string& speech,
const char* texttype, std::string lang, Bscript::ObjArray* speechtokens )
{
addMember( "type", new BLong( Core::EVID_SPOKE ) );
addMember( "source", new Module::EOfflineCharacterRefObjImp( speaker ) );
addMember( "text", new String( speech ) );
addMember( "texttype", new String( texttype ) );
if ( !lang.empty() )
addMember( "langcode", new String( lang ) );
if ( speechtokens != nullptr )
addMember( "tokens", speechtokens );
}
DamageEvent::DamageEvent( Mobile::Character* source, unsigned short damage )
{
addMember( "type", new BLong( Core::EVID_DAMAGED ) );
if ( source != nullptr )
addMember( "source", new Module::EOfflineCharacterRefObjImp( source ) );
else
addMember( "source", new BLong( 0 ) );
addMember( "damage", new BLong( damage ) );
}
ItemGivenEvent::ItemGivenEvent( Mobile::Character* chr_givenby, Items::Item* item_given,
Mobile::NPC* chr_givento )
: SourcedEvent( Core::EVID_ITEM_GIVEN, chr_givenby ), given_by_( nullptr )
{
addMember( "item", new EItemRefObjImp( item_given ) );
given_time_ = Core::read_gameclock();
item_.set( item_given );
cont_.set( item_given->container );
given_by_.set( chr_givenby );
item_given->setprop( "GivenBy", BLong::pack( chr_givenby->serial ) );
item_given->setprop( "GivenTo", BLong::pack( chr_givento->serial ) );
item_given->setprop( "GivenTime", BLong::pack( given_time_ ) );
}
ItemGivenEvent::~ItemGivenEvent()
{
/* See if the item is still in the container it was in
This means the AI script didn't do anything with it.
*/
Items::Item* item = item_.get();
Core::UContainer* cont = cont_.get();
Mobile::Character* chr = given_by_.get();
std::string given_time_str;
if ( !item->getprop( "GivenTime", given_time_str ) )
given_time_str = "";
item->eraseprop( "GivenBy" );
item->eraseprop( "GivenTo" );
item->eraseprop( "GivenTime" );
Bscript::BObject given_value( BObjectImp::unpack( given_time_str.c_str() ) );
int gts = static_cast<BLong*>( given_value.impptr() )->value();
if ( item->orphan() || cont->orphan() || chr->orphan() )
return;
if ( item->container == cont && Clib::tostring( given_time_ ) == Clib::tostring( gts ) )
{
Core::UContainer* backpack = chr->backpack();
if ( backpack != nullptr && !chr->dead() )
{
if ( backpack->can_add( *item ) )
{
cont->remove( item );
u8 newSlot = 1;
if ( !backpack->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
{
const Core::Pos4d newpos = chr->pos();
const Core::Pos4d oldpos = item->pos();
item->setposition( newpos );
add_item_to_world( item );
register_with_supporting_multi( item );
move_item( item, newpos, oldpos );
return;
}
backpack->add( item );
update_item_to_inrange( item );
return;
}
}
cont->remove( item );
const Core::Pos4d newpos = chr->pos();
const Core::Pos4d oldpos = item->pos();
item->setposition( newpos );
add_item_to_world( item );
register_with_supporting_multi( item );
move_item( item, newpos, oldpos );
}
}
} // namespace Module
namespace Core
{
bool UObject::script_isa( unsigned isatype ) const
{
return ( isatype == POLCLASS_OBJECT );
}
bool ULockable::script_isa( unsigned isatype ) const
{
return ( isatype == POLCLASS_LOCKABLE ) || base::script_isa( isatype );
}
bool UContainer::script_isa( unsigned isatype ) const
{
return ( isatype == POLCLASS_CONTAINER ) || base::script_isa( isatype );
}
bool UCorpse::script_isa( unsigned isatype ) const
{
return ( isatype == POLCLASS_CORPSE ) || base::script_isa( isatype );
}
bool UDoor::script_isa( unsigned isatype ) const
{
return ( isatype == POLCLASS_DOOR ) || base::script_isa( isatype );
}
bool Spellbook::script_isa( unsigned isatype ) const
{
return ( isatype == POLCLASS_SPELLBOOK ) || base::script_isa( isatype );
}
bool Map::script_isa( unsigned isatype ) const
{
return ( isatype == POLCLASS_MAP ) || base::script_isa( isatype );
}
} // namespace Core
namespace Items
{
bool Item::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_ITEM ) || base::script_isa( isatype );
}
bool Equipment::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_EQUIPMENT ) || base::script_isa( isatype );
}
bool UArmor::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_ARMOR ) || base::script_isa( isatype );
}
bool UWeapon::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_WEAPON ) || base::script_isa( isatype );
}
} // namespace Items
namespace Mobile
{
bool Character::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_MOBILE ) || base::script_isa( isatype );
}
bool NPC::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_NPC ) || base::script_isa( isatype );
}
} // namespace Mobile
namespace Multi
{
bool UMulti::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_MULTI ) || base::script_isa( isatype );
}
bool UBoat::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_BOAT ) || base::script_isa( isatype );
}
bool UHouse::script_isa( unsigned isatype ) const
{
return ( isatype == Core::POLCLASS_HOUSE ) || base::script_isa( isatype );
}
} // namespace Multi
} // namespace Pol