• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 25990848974

17 May 2026 12:27PM UTC coverage: 60.822% (-0.08%) from 60.903%
25990848974

Pull #884

github

turleypol
listhostiles and attack_once accept now Attackable
Pull Request #884: Attackable item

268 of 575 new or added lines in 26 files covered. (46.61%)

17 existing lines in 7 files now uncovered.

44719 of 73524 relevant lines covered (60.82%)

513395.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.6
/pol-core/pol/uoscrobj.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2005/01/24 Shinigami: added ObjMember character.spyonclient2 to get data from packet 0xd9 (Spy
5
 * on Client 2)
6
 * - 2005/03/09 Shinigami: Added Prop Character::Delay_Mod [ms] for WeaponDelay
7
 * - 2005/04/02 Shinigami: UBoat::script_method_id & UBoat::script_method - added optional realm
8
 * param
9
 * - 2005/04/04 Shinigami: Added Prop Character::CreatedAt [PolClock]
10
 * - 2005/08/29 Shinigami: get-/setspyonclient2 renamed to get-/setclientinfo
11
 * - 2005/11/26 Shinigami: changed "strcmp" into "stricmp" to suppress Script Errors
12
 * - 2005/12/09 MuadDib:   Added uclang member for storing UC language from client.
13
 * - 2005/12/09 MuadDib:   Fixed ~ItemGivenEvent not returning items correctly if the script
14
 *                         did nothing with it. Was incorrect str/int comparision for times.
15
 * - 2006/05/16 Shinigami: added Prop Character.Race [RACE_* Constants] to support Elfs
16
 * - 2006/06/15 Austin:    Added mobile.Privs()
17
 * - 2007/07/09 Shinigami: added Prop Character.isUOKR [bool] - UO:KR client used?
18
 * - 2008/07/08 Turley:    Added character.movemode - returns the MoveMode like given in NPCDesc
19
 *                         Added item.stackable - Is item stackable?
20
 * - 2008/12/17 MuadDub:   Added item.tile_layer - returns layer entry from tiledata/tiles.cfg
21
 * - 2009/07/20 MuadDib:   ReAdded on_facing_change() to MBR_FACING: for items.
22
 * - 2009/08/06 MuadDib:   Added gotten_by code for items.
23
 * - 2009/08/31 MuadDib:   Changed layer check on graphic change, excluding mount layer entirely.
24
 * - 2009/09/03 MuadDib:   Relocation of account related cpp/h
25
 *                         Relocation of multi related cpp/h
26
 * - 2009/09/06 Turley:    Removed isUOKR added ClientType
27
 * - 2009/09/22 MuadDib:   Rewrite for Character/NPC to use ar(), ar_mod(), ar_mod(newvalue)
28
 * virtuals.
29
 * - 2009/10/09 Turley:    Added spellbook.spells() & .hasspell() methods
30
 * - 2009/10/10 Turley:    Added spellbook.addspell() & .removespell() methods
31
 * - 2009/10/14 Turley:    Added char.deaf() methods & char.deafened member
32
 * -            MuadDib:   Squelch and Deaf members set to return the gameclock they are in effect
33
 * till.
34
 * - 2009/10/17 Turley:    Moved PrivUpdater to charactr.cpp - Tomi
35
 * - 2009/11/19 Turley:    lightlevel now supports endless duration - Tomi
36
 * - 2009/12/02 Turley:    gargoyle race support
37
 * - 2009/12/03 Turley:    added gargoyle flying movemode
38
 * - 2009/12/21 Turley:    ._method() call fix
39
 *                         multi support of methodscripts
40
 * - 2010/01/15 Turley:    (Tomi) season stuff
41
 * - 2010/02/03 Turley:    MethodScript support for mobiles
42
 * - 2011/12/13 Tomi:      Boat members MBR_COMPONENT, MBR_HULL, MBR_ROPE, MBR_SAILS, MBR_WHEEL,
43
 * MBR_TILLER, MBR_RUDDER, MBR_STORAGE, MBR_WEAPONSLOT
44
 * - 2012/02/02 Tomi:      Added boat member MBR_MULTIID
45
 * - 2012/03/26 Tomi:      Added MBR_LASTCOORD
46
 * - 2012/04/14 Tomi:      Added MBR_FACETID for new map message packet
47
 * - 2012/04/15 Tomi:      Added MBR_EDITABLE for maps
48
 * - 2012/06/02 Tomi:      Added MBR_ACTIVE_SKILL and MBR_CASTING_SPELL for characters
49
 */
50

51

52
#include "uoscrobj.h"
53

54
#include <memory>
55
#include <string>
56

57
#include "../bscript/berror.h"
58
#include "../bscript/dict.h"
59
#include "../bscript/execmodl.h"
60
#include "../bscript/executor.h"
61
#include "../bscript/impstr.h"
62
#include "../bscript/objmembers.h"
63
#include "../bscript/objmethods.h"
64
#include "../clib/clib.h"
65
#include "../clib/stlutil.h"
66
#include "../plib/poltype.h"
67
#include "../plib/uconst.h"
68
#include "accounts/account.h"
69
#include "accounts/acscrobj.h"
70
#include "cmdlevel.h"
71
#include "containr.h"
72
#include "door.h"
73
#include "dynproperties.h"
74
#include "equipdsc.h"
75
#include "eventid.h"
76
#include "exscrobj.h"
77
#include "fnsearch.h"
78
#include "globals/network.h"
79
#include "globals/uvars.h"
80
#include "item/armor.h"
81
#include "item/equipmnt.h"
82
#include "item/item.h"
83
#include "item/itemdesc.h"
84
#include "item/weapon.h"
85
#include "lockable.h"
86
#include "mobile/attack.h"
87
#include "mobile/charactr.h"
88
#include "mobile/corpse.h"
89
#include "mobile/npc.h"
90
#include "mobile/ufacing.h"
91
#include "module/guildmod.h"
92
#include "module/partymod.h"
93
#include "module/uomod.h"
94
#include "multi/boat.h"
95
#include "multi/boatcomp.h"
96
#include "multi/house.h"
97
#include "multi/multi.h"
98
#include "network/cgdata.h"
99
#include "network/client.h"
100
#include "network/packethelper.h"
101
#include "network/packets.h"
102
#include "network/pktdef.h"
103
#include "npctmpl.h"
104
#include "polclass.h"
105
#include "polclock.h"
106
#include "proplist.h"
107
#include "realms/realm.h"
108
#include "realms/realms.h"
109
#include "spelbook.h"
110
#include "statmsg.h"
111
#include "syshookscript.h"
112
#include "tooltips.h"
113
#include "ufunc.h"
114
#include "umap.h"
115
#include "uobject.h"
116
#include "uoclient.h"
117
#include "uoexec.h"
118
#include "uworld.h"
119

120
namespace Pol
121
{
122
namespace Module
123
{
124
using namespace Bscript;
125

126
BApplicObjType euboatrefobjimp_type;
127
BApplicObjType emultirefobjimp_type;
128
BApplicObjType eitemrefobjimp_type;
129
BApplicObjType echaracterrefobjimp_type;
130
BApplicObjType echaracterequipobjimp_type;
131
BApplicObjType storage_area_type;
132
BApplicObjType menu_type;
133
BApplicObjType eclientrefobjimp_type;
134

135
const char* ECharacterRefObjImp::typeOf() const
59✔
136
{
137
  return "MobileRef";
59✔
138
}
139
u8 ECharacterRefObjImp::typeOfInt() const
×
140
{
141
  return OTMobileRef;
×
142
}
143

144
BObjectImp* ECharacterRefObjImp::copy() const
924✔
145
{
146
  return new ECharacterRefObjImp( obj_.get() );
924✔
147
}
148

149
BObjectRef ECharacterRefObjImp::get_member_id( const int id )
746✔
150
{
151
  BObjectImp* result = obj_->get_script_member_id( id );
746✔
152
  if ( result != nullptr )
746✔
153
    return BObjectRef( result );
746✔
154
  return BObjectRef( UninitObject::create() );
×
155
}
156

157
BObjectRef ECharacterRefObjImp::get_member( const char* membername )
×
158
{
159
  ObjMember* objmember = getKnownObjMember( membername );
×
160
  if ( objmember != nullptr )
×
161
    return this->get_member_id( objmember->id );
×
162
  return BObjectRef( UninitObject::create() );
×
163
}
164

165
BObjectRef ECharacterRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
48✔
166
{
167
  BObjectImp* result = nullptr;
48✔
168
  if ( auto* l = impptrIf<BLong>( value ) )
48✔
169
    result = obj_->set_script_member_id( id, l->value() );
35✔
170
  else if ( auto* s = impptrIf<String>( value ) )
13✔
171
    result = obj_->set_script_member_id( id, s->value() );
13✔
172
  else if ( auto* d = impptrIf<Double>( value ) )
×
173
    result = obj_->set_script_member_id_double( id, d->value() );
×
174
  if ( result != nullptr )
48✔
175
    return BObjectRef( result );
42✔
176
  return BObjectRef( UninitObject::create() );
6✔
177
}
178

179
BObjectRef ECharacterRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
×
180
{
181
  ObjMember* objmember = getKnownObjMember( membername );
×
182
  if ( objmember != nullptr )
×
183
    return this->set_member_id( objmember->id, value, copy );
×
184
  return BObjectRef( UninitObject::create() );
×
185
}
186

187
BObjectImp* ECharacterRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
393✔
188
                                                    bool forcebuiltin )
189
{
190
  // MethodScript for npcs in npc->template_ (npctmpl.h) (aka templatebased)
191
  //             for chars in uoclient_general (uoclient.h) (aka one global definition)
192
  if ( obj_->orphan() )
393✔
193
    return new BError( "That object no longer exists" );
1✔
194
  ObjMethod* mth = getObjMethod( id );
392✔
195
  if ( mth->overridden && !forcebuiltin )
392✔
196
  {
197
    BObjectImp* imp = obj_->custom_script_method( mth->code, ex );
×
198
    if ( imp )
×
199
      return imp;
×
200
  }
201
  BObjectImp* imp = obj_->script_method_id( id, ex );
392✔
202
  if ( imp != nullptr )
392✔
203
    return imp;
392✔
204
  return base::call_polmethod_id( id, ex );
×
205
}
206

207
BObjectImp* ECharacterRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
×
208
{
209
  // MethodScript for npcs in npc->template_ (npctmpl.h) (aka templatebased)
210
  //             for chars in uoclient_general (uoclient.h) (aka one global definition)
211
  bool forcebuiltin{ Executor::builtinMethodForced( methodname ) };
×
212
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
213
  if ( objmethod != nullptr )
×
214
    return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
×
215
  BObjectImp* imp = obj_->custom_script_method( methodname, ex );
×
216
  if ( imp )
×
217
    return imp;
×
218
  return base::call_polmethod( methodname, ex );
×
219
}
220

221
bool ECharacterRefObjImp::isTrue() const
126✔
222
{
223
  return ( !obj_->orphan() && obj_->logged_in() );
126✔
224
}
225

226
bool ECharacterRefObjImp::operator==( const BObjectImp& objimp ) const
41✔
227
{
228
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
41✔
229
  {
230
    const BApplicObjBase* aob =
231
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
41✔
232

233
    if ( aob->object_type() == &echaracterrefobjimp_type )
41✔
234
    {
235
      const ECharacterRefObjImp* chrref_imp =
236
          Clib::explicit_cast<const ECharacterRefObjImp*, const BApplicObjBase*>( aob );
41✔
237

238
      return ( chrref_imp->obj_->serial == obj_->serial );
41✔
239
    }
240
    return false;
×
241
  }
242
  if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
×
243
    return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
×
244
  return false;
×
245
}
246

247
bool ECharacterRefObjImp::operator<( const BObjectImp& objimp ) const
×
248
{
249
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
×
250
  {
251
    const BApplicObjBase* aob =
252
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
×
253

254
    if ( aob->object_type() == &echaracterrefobjimp_type )
×
255
    {
256
      const ECharacterRefObjImp* chrref_imp =
257
          Clib::explicit_cast<const ECharacterRefObjImp*, const BApplicObjBase*>( aob );
×
258

259
      return ( chrref_imp->obj_->serial < obj_->serial );
×
260
    }
261
    if ( aob->object_type() == &eitemrefobjimp_type )
×
262
      return true;
×
263
    return false;
×
264
  }
265
  return base::operator<( objimp );
×
266
}
267

268
const char* EOfflineCharacterRefObjImp::typeOf() const
9✔
269
{
270
  return "OfflineMobileRef";
9✔
271
}
272
u8 EOfflineCharacterRefObjImp::typeOfInt() const
×
273
{
274
  return OTOfflineMobileRef;
×
275
}
276

277
BObjectImp* EOfflineCharacterRefObjImp::copy() const
102✔
278
{
279
  return new EOfflineCharacterRefObjImp( obj_.get() );
102✔
280
}
281

282
bool EOfflineCharacterRefObjImp::isTrue() const
46✔
283
{
284
  return ( !obj_->orphan() );
46✔
285
}
286

287
const char* EItemRefObjImp::typeOf() const
150✔
288
{
289
  return "ItemRef";
150✔
290
}
291
u8 EItemRefObjImp::typeOfInt() const
×
292
{
293
  return OTItemRef;
×
294
}
295

296
BObjectImp* EItemRefObjImp::copy() const
575✔
297
{
298
  return new EItemRefObjImp( obj_.get() );
575✔
299
}
300

301
BObjectRef EItemRefObjImp::get_member_id( const int id )
552✔
302
{
303
  BObjectImp* result = obj_->get_script_member_id( id );
552✔
304
  if ( result != nullptr )
552✔
305
    return BObjectRef( result );
552✔
306
  return BObjectRef( UninitObject::create() );
×
307
}
308

309
BObjectRef EItemRefObjImp::get_member( const char* membername )
×
310
{
311
  ObjMember* objmember = getKnownObjMember( membername );
×
312
  if ( objmember != nullptr )
×
313
    return this->get_member_id( objmember->id );
×
314
  return BObjectRef( UninitObject::create() );
×
315
}
316

317
BObjectRef EItemRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
47✔
318
{
319
  BObjectImp* result = nullptr;
47✔
320
  if ( auto* l = impptrIf<BLong>( value ) )
47✔
321
    result = obj_->set_script_member_id( id, l->value() );
30✔
322
  else if ( auto* s = impptrIf<String>( value ) )
17✔
323
    result = obj_->set_script_member_id( id, s->value() );
9✔
324
  else if ( auto* d = impptrIf<Double>( value ) )
8✔
325
    result = obj_->set_script_member_id_double( id, d->value() );
8✔
326
  if ( result != nullptr )
47✔
327
    return BObjectRef( result );
47✔
328
  return BObjectRef( UninitObject::create() );
×
329
}
330

331
BObjectRef EItemRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
×
332
{
333
  ObjMember* objmember = getKnownObjMember( membername );
×
334
  if ( objmember != nullptr )
×
335
    return this->set_member_id( objmember->id, value, copy );
×
336
  return BObjectRef( UninitObject::create() );
×
337
}
338

339
BObjectImp* EItemRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
227✔
340
                                               bool forcebuiltin )
341
{
342
  if ( obj_->orphan() )
227✔
343
    return new BError( "That object no longer exists" );
×
344

345
  ObjMethod* mth = getObjMethod( id );
227✔
346
  if ( mth->overridden && !forcebuiltin )
227✔
347
  {
348
    BObjectImp* imp = obj_->custom_script_method( mth->code, ex );
×
349
    if ( imp )
×
350
      return imp;
×
351
  }
352
  BObjectImp* imp = obj_->script_method_id( id, ex );
227✔
353
  if ( imp != nullptr )
227✔
354
    return imp;
227✔
355
  return base::call_polmethod_id( id, ex );
×
356
}
357

358
BObjectImp* EItemRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
4✔
359
{
360
  bool forcebuiltin{ Executor::builtinMethodForced( methodname ) };
4✔
361

362
  ObjMethod* objmethod = getKnownObjMethod( methodname );
4✔
363
  if ( objmethod != nullptr )
4✔
364
    return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
×
365
  Items::Item* item = obj_.get();
4✔
366
  BObjectImp* imp = item->custom_script_method( methodname, ex );
4✔
367
  if ( imp )
4✔
368
    return imp;
4✔
369
  return base::call_polmethod( methodname, ex );
×
370
}
371

372
bool EItemRefObjImp::isTrue() const
242✔
373
{
374
  return ( !obj_->orphan() );
242✔
375
}
376

377
bool EItemRefObjImp::operator==( const BObjectImp& objimp ) const
35✔
378
{
379
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
35✔
380
  {
381
    const BApplicObjBase* aob =
382
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
35✔
383

384
    if ( aob->object_type() == &eitemrefobjimp_type )
35✔
385
    {
386
      const EItemRefObjImp* itemref_imp =
387
          Clib::explicit_cast<const EItemRefObjImp*, const BApplicObjBase*>( aob );
35✔
388

389
      return ( itemref_imp->obj_->serial == obj_->serial );
35✔
390
    }
391
    return false;
×
392
  }
393
  if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
×
394
    return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
×
395
  return false;
×
396
}
397

398
bool EItemRefObjImp::operator<( const BObjectImp& objimp ) const
×
399
{
400
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
×
401
  {
402
    const BApplicObjBase* aob =
403
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
×
404

405
    if ( aob->object_type() == &eitemrefobjimp_type )
×
406
    {
407
      const EItemRefObjImp* itemref_imp =
408
          Clib::explicit_cast<const EItemRefObjImp*, const BApplicObjBase*>( aob );
×
409

410
      return ( itemref_imp->obj_->serial < obj_->serial );
×
411
    }
412
    return ( &eitemrefobjimp_type < aob->object_type() );
×
413
  }
414

415
  return base::operator<( objimp );
×
416
}
417

418
const char* EUBoatRefObjImp::typeOf() const
12✔
419
{
420
  return "BoatRef";
12✔
421
}
422
u8 EUBoatRefObjImp::typeOfInt() const
×
423
{
424
  return OTBoatRef;
×
425
}
426

427
BObjectImp* EUBoatRefObjImp::copy() const
80✔
428
{
429
  return new EUBoatRefObjImp( obj_.get() );
80✔
430
}
431

432
BObjectRef EUBoatRefObjImp::get_member_id( const int id )
6,157✔
433
{
434
  BObjectImp* result = obj_->get_script_member_id( id );
6,157✔
435
  if ( result != nullptr )
6,157✔
436
    return BObjectRef( result );
6,157✔
437
  return BObjectRef( UninitObject::create() );
×
438
}
439

440
BObjectRef EUBoatRefObjImp::get_member( const char* membername )
×
441
{
442
  ObjMember* objmember = getKnownObjMember( membername );
×
443
  if ( objmember != nullptr )
×
444
    return this->get_member_id( objmember->id );
×
445
  return BObjectRef( UninitObject::create() );
×
446
}
447

448
BObjectRef EUBoatRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
2✔
449
{
450
  BObjectImp* result = nullptr;
2✔
451
  if ( auto* l = impptrIf<BLong>( value ) )
2✔
452
    result = obj_->set_script_member_id( id, l->value() );
1✔
453
  else if ( auto* s = impptrIf<String>( value ) )
1✔
454
    result = obj_->set_script_member_id( id, s->value() );
1✔
455
  else if ( auto* d = impptrIf<Double>( value ) )
×
456
    result = obj_->set_script_member_id_double( id, d->value() );
×
457
  if ( result != nullptr )
2✔
458
    return BObjectRef( result );
2✔
459
  return BObjectRef( UninitObject::create() );
×
460
}
461

462
BObjectRef EUBoatRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
×
463
{
464
  ObjMember* objmember = getKnownObjMember( membername );
×
465
  if ( objmember != nullptr )
×
466
    return this->set_member_id( objmember->id, value, copy );
×
467
  return BObjectRef( UninitObject::create() );
×
468
}
469

470
BObjectImp* EUBoatRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
43✔
471
                                                bool forcebuiltin )
472
{
473
  if ( obj_->orphan() )
43✔
474
    return new BError( "That object no longer exists" );
×
475

476
  ObjMethod* mth = getObjMethod( id );
43✔
477
  if ( mth->overridden && !forcebuiltin )
43✔
478
  {
479
    BObjectImp* imp = obj_->custom_script_method( mth->code, ex );
×
480
    if ( imp )
×
481
      return imp;
×
482
  }
483
  BObjectImp* imp = obj_->script_method_id( id, ex );
43✔
484
  if ( imp != nullptr )
43✔
485
    return imp;
43✔
486
  return base::call_polmethod_id( id, ex );
×
487
}
488

489
BObjectImp* EUBoatRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
3✔
490
{
491
  bool forcebuiltin{ Executor::builtinMethodForced( methodname ) };
3✔
492
  ObjMethod* objmethod = getKnownObjMethod( methodname );
3✔
493
  if ( objmethod != nullptr )
3✔
494
    return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
×
495

496
  Multi::UBoat* boat = obj_.get();
3✔
497
  BObjectImp* imp = boat->custom_script_method( methodname, ex );
3✔
498
  if ( imp )
3✔
499
    return imp;
3✔
500

501
  return base::call_polmethod( methodname, ex );
×
502
}
503

504
bool EUBoatRefObjImp::isTrue() const
117✔
505
{
506
  return ( !obj_->orphan() );
117✔
507
}
508

509
bool EUBoatRefObjImp::operator==( const BObjectImp& objimp ) const
×
510
{
511
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
×
512
  {
513
    const BApplicObjBase* aob =
514
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
×
515

516
    if ( aob->object_type() == &euboatrefobjimp_type )
×
517
    {
518
      const EUBoatRefObjImp* boatref_imp =
519
          Clib::explicit_cast<const EUBoatRefObjImp*, const BApplicObjBase*>( aob );
×
520

521
      return ( boatref_imp->obj_->serial == obj_->serial );
×
522
    }
523
    return false;
×
524
  }
525
  if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
×
526
    return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
×
527
  return false;
×
528
}
529

530
BObjectImp* EMultiRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
×
531
{
532
  bool forcebuiltin{ Executor::builtinMethodForced( methodname ) };
×
533
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
534
  if ( objmethod != nullptr )
×
535
    return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
×
536
  Multi::UMulti* multi = obj_.get();
×
537
  BObjectImp* imp = multi->custom_script_method( methodname, ex );
×
538
  if ( imp )
×
539
    return imp;
×
540
  return base::call_polmethod( methodname, ex );
×
541
}
542

543
BObjectImp* EMultiRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
14✔
544
                                                bool forcebuiltin )
545
{
546
  Multi::UMulti* multi = obj_.get();
14✔
547
  if ( multi->orphan() )
14✔
548
    return new BError( "That object no longer exists" );
×
549

550
  ObjMethod* mth = getObjMethod( id );
14✔
551
  if ( mth->overridden && !forcebuiltin )
14✔
552
  {
553
    BObjectImp* imp = multi->custom_script_method( mth->code, ex );
×
554
    if ( imp )
×
555
      return imp;
×
556
  }
557

558
  BObjectImp* imp = multi->script_method_id( id, ex );
14✔
559
  if ( imp != nullptr )
14✔
560
    return imp;
14✔
561
  return base::call_polmethod_id( id, ex, forcebuiltin );
×
562
}
563

564
const char* EMultiRefObjImp::typeOf() const
44✔
565
{
566
  return "MultiRef";
44✔
567
}
568
u8 EMultiRefObjImp::typeOfInt() const
×
569
{
570
  return OTMultiRef;
×
571
}
572

573
BObjectImp* EMultiRefObjImp::copy() const
57✔
574
{
575
  return new EMultiRefObjImp( obj_.get() );
57✔
576
}
577

578
BObjectRef EMultiRefObjImp::get_member_id( const int id )
53✔
579
{
580
  BObjectImp* result = obj_->get_script_member_id( id );
53✔
581
  if ( result != nullptr )
53✔
582
    return BObjectRef( result );
53✔
583
  return BObjectRef( UninitObject::create() );
×
584
}
585

586
BObjectRef EMultiRefObjImp::get_member( const char* membername )
×
587
{
588
  ObjMember* objmember = getKnownObjMember( membername );
×
589
  if ( objmember != nullptr )
×
590
    return this->get_member_id( objmember->id );
×
591
  return BObjectRef( UninitObject::create() );
×
592
}
593

594
BObjectRef EMultiRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
2✔
595
{
596
  BObjectImp* result = nullptr;
2✔
597
  if ( auto* l = impptrIf<BLong>( value ) )
2✔
598
    result = obj_->set_script_member_id( id, l->value() );
×
599
  else if ( auto* s = impptrIf<String>( value ) )
2✔
600
    result = obj_->set_script_member_id( id, s->value() );
2✔
601
  else if ( auto* d = impptrIf<Double>( value ) )
×
602
    result = obj_->set_script_member_id_double( id, d->value() );
×
603
  if ( result != nullptr )
2✔
604
    return BObjectRef( result );
2✔
605
  return BObjectRef( UninitObject::create() );
×
606
}
607
BObjectRef EMultiRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
×
608
{
609
  ObjMember* objmember = getKnownObjMember( membername );
×
610
  if ( objmember != nullptr )
×
611
    return this->set_member_id( objmember->id, value, copy );
×
612
  return BObjectRef( UninitObject::create() );
×
613
}
614

615
bool EMultiRefObjImp::isTrue() const
22✔
616
{
617
  return ( !obj_->orphan() );
22✔
618
}
619

620
bool EMultiRefObjImp::operator==( const BObjectImp& objimp ) const
3✔
621
{
622
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
3✔
623
  {
624
    const BApplicObjBase* aob =
625
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
3✔
626

627
    if ( aob->object_type() == &emultirefobjimp_type )
3✔
628
    {
629
      const EMultiRefObjImp* multiref_imp =
630
          Clib::explicit_cast<const EMultiRefObjImp*, const BApplicObjBase*>( aob );
3✔
631

632
      return ( multiref_imp->obj_->serial == obj_->serial );
3✔
633
    }
634
    return false;
×
635
  }
636
  if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
×
637
    return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
×
638
  return false;
×
639
}
640
}  // namespace Module
641

642
namespace Core
643
{
644
using namespace Bscript;
645

646
BObjectImp* UObject::get_script_member_id( const int id ) const
7,781✔
647
{
648
  if ( orphan() )
7,781✔
649
    return new UninitObject;
20✔
650
  switch ( id )
7,761✔
651
  {
652
  case MBR_X:
185✔
653
    return new BLong( x() );
185✔
654
    break;
655
  case MBR_Y:
173✔
656
    return new BLong( y() );
173✔
657
    break;
658
  case MBR_Z:
154✔
659
    return new BLong( z() );
154✔
660
    break;
661
  case MBR_NAME:
45✔
662
    return new String( name() );
45✔
663
    break;
664
  case MBR_OBJTYPE:
2✔
665
    return new BLong( objtype_ );
2✔
666
    break;
667
  case MBR_GRAPHIC:
5✔
668
    return new BLong( graphic );
5✔
669
    break;
670
  case MBR_SERIAL:
546✔
671
    return new BLong( serial );
546✔
672
    break;
673
  case MBR_COLOR:
1✔
674
    return new BLong( color );
1✔
675
    break;
676
  case MBR_HEIGHT:
22✔
677
    return new BLong( height );
22✔
678
    break;
679
  case MBR_FACING:
5✔
680
    return new BLong( facing );
5✔
681
    break;
682
  case MBR_DIRTY:
×
683
    return new BLong( dirty() ? 1 : 0 );
×
684
    break;
685
  case MBR_WEIGHT:
42✔
686
    return new BLong( weight() );
42✔
687
    break;
688
  case MBR_MULTI:
7✔
689
    if ( realm() != nullptr )
7✔
690
    {
691
      Multi::UMulti* multi;
692
      if ( nullptr != ( multi = realm()->find_supporting_multi( pos3d() ) ) )
7✔
693
        return multi->make_ref();
3✔
694
      return new BLong( 0 );
4✔
695
    }
696
    else
697
      return new BLong( 0 );
×
698
    break;
699
  case MBR_REALM:
6,056✔
700
    if ( realm() != nullptr )
6,056✔
701
      return new String( realm()->name() );
6,056✔
702
    else
703
      return new BError( "object does not belong to a realm." );
×
704
    break;
705
  case MBR_SPECIFIC_NAME:
×
706
    return new BLong( specific_name() );
×
707
  default:
518✔
708
    return nullptr;
518✔
709
  }
710
}
711

712
BObjectImp* UObject::get_script_member( const char* membername ) const
×
713
{
714
  ObjMember* objmember = getKnownObjMember( membername );
×
715
  if ( objmember != nullptr )
×
716
    return this->get_script_member_id( objmember->id );
×
717
  return nullptr;
×
718
}
719

720
BObjectImp* UObject::set_script_member_id( const int id, const std::string& value )
38✔
721
{
722
  if ( orphan() )
38✔
723
    return new UninitObject;
×
724

725
  set_dirty();
38✔
726
  switch ( id )
38✔
727
  {
728
  case MBR_NAME:
14✔
729
    if ( ismobile() && ( value.empty() || isspace( value[0] ) ) )
14✔
730
      return new BError( "mobile.name must not be empty, and must not begin with a space" );
×
731
    setname( value );
14✔
732
    return new String( name() );
14✔
733
    break;
734
  default:
24✔
735
    return nullptr;
24✔
736
  }
737
}
738

739
BObjectImp* UObject::set_script_member( const char* membername, const std::string& value )
×
740
{
741
  ObjMember* objmember = getKnownObjMember( membername );
×
742
  if ( objmember != nullptr )
×
743
    return this->set_script_member_id( objmember->id, value );
×
744
  return nullptr;
×
745
}
746

747
BObjectImp* UObject::set_script_member_id( const int id, int value )
236✔
748
{
749
  if ( orphan() )
236✔
750
    return new UninitObject;
×
751

752
  set_dirty();
236✔
753
  switch ( id )
236✔
754
  {
755
  case MBR_GRAPHIC:
1✔
756
    setgraphic( Clib::clamp_convert<u16>( value ) );
1✔
757
    return new BLong( graphic );
1✔
758
  case MBR_COLOR:
1✔
759
  {
760
    bool res = setcolor( Clib::clamp_convert<u16>( value ) );
1✔
761
    if ( !res )  // TODO log?
1✔
762
      return new BError( "Invalid color value " + Clib::hexint( value ) );
×
763
    return new BLong( color );
1✔
764
  }
765
  default:
234✔
766
    return nullptr;
234✔
767
  }
768
}
769

770
BObjectImp* UObject::set_script_member( const char* membername, int value )
×
771
{
772
  ObjMember* objmember = getKnownObjMember( membername );
×
773
  if ( objmember != nullptr )
×
774
    return this->set_script_member_id( objmember->id, value );
×
775
  return nullptr;
×
776
}
777

778
BObjectImp* UObject::set_script_member_id_double( const int /*id*/, double /*value*/ )
19✔
779
{
780
  set_dirty();
19✔
781
  return nullptr;
19✔
782
}
783

784
BObjectImp* UObject::set_script_member_double( const char* membername, double value )
4✔
785
{
786
  ObjMember* objmember = getKnownObjMember( membername );
4✔
787
  if ( objmember != nullptr )
4✔
788
    return this->set_script_member_id_double( objmember->id, value );
4✔
789
  return nullptr;
×
790
}
791
}  // namespace Core
792

793
namespace Items
794
{
795
using namespace Bscript;
796

797
BObjectImp* Item::get_script_member_id( const int id ) const
6,865✔
798
{
799
  BObjectImp* imp = base::get_script_member_id( id );
6,865✔
800
  if ( imp != nullptr )
6,865✔
801
    return imp;
6,641✔
802

803
  switch ( id )
224✔
804
  {
805
  case MBR_AMOUNT:
7✔
806
    return new BLong( amount_ );
7✔
807
    break;
808
  case MBR_LAYER:
1✔
809
    return new BLong( layer );
1✔
810
    break;
811
  case MBR_TILE_LAYER:
×
812
    return new BLong( tile_layer );
×
813
    break;
814
  case MBR_CONTAINER:
8✔
815
    if ( container != nullptr )
8✔
816
      return container->make_ref();
8✔
817
    return new BLong( 0 );
×
818
    break;
819
  case MBR_USESCRIPT:
1✔
820
    return new String( on_use_script_ );
1✔
821
    break;
822
  case MBR_SNOOPSCRIPT:
1✔
823
    return new String( snoop_script_ );
1✔
824
    break;
825
  case MBR_EQUIPSCRIPT:
1✔
826
    return new String( equip_script_ );
1✔
827
    break;
828
  case MBR_UNEQUIPSCRIPT:
1✔
829
    return new String( unequip_script_ );
1✔
830
    break;
831
  case MBR_DESC:
×
832
    return new String( description() );
×
833
    break;
834
  case MBR_MOVABLE:
1✔
835
    return new BLong( movable() ? 1 : 0 );
1✔
836
    break;
837
  case MBR_INVISIBLE:
1✔
838
    return new BLong( invisible() ? 1 : 0 );
1✔
839
    break;
840
  case MBR_CURSED:
2✔
841
    return new BLong( cursed() ? 1 : 0 );
2✔
842
    break;
843
  case MBR_DECAYAT:
1✔
844
    return new BLong( decayat_gameclock_ );
1✔
845
    break;
846
  case MBR_SELLPRICE:
1✔
847
    return new BLong( sellprice() );
1✔
848
    break;
849
  case MBR_BUYPRICE:
1✔
850
    return new BLong( buyprice() );
1✔
851
    break;
852
  case MBR_NEWBIE:
1✔
853
    return new BLong( newbie() ? 1 : 0 );
1✔
854
    break;
855
  case MBR_INSURED:
1✔
856
    return new BLong( insured() ? 1 : 0 );
1✔
857
    break;
858
  case MBR_ITEM_COUNT:
×
859
    return new BLong( item_count() );
×
860
    break;
861
  case MBR_STACKABLE:
×
862
    return new BLong( stackable() ? 1 : 0 );
×
863
    break;
864
  case MBR_SAVEONEXIT:
×
865
    return new BLong( saveonexit() );
×
866
    break;
867
  case MBR_FIRE_RESIST:
1✔
868
    return new BLong( fire_resist().sum() );
1✔
869
    break;
870
  case MBR_COLD_RESIST:
1✔
871
    return new BLong( cold_resist().sum() );
1✔
872
    break;
873
  case MBR_ENERGY_RESIST:
1✔
874
    return new BLong( energy_resist().sum() );
1✔
875
    break;
876
  case MBR_POISON_RESIST:
1✔
877
    return new BLong( poison_resist().sum() );
1✔
878
    break;
879
  case MBR_PHYSICAL_RESIST:
1✔
880
    return new BLong( physical_resist().sum() );
1✔
881
    break;
882
  case MBR_LOWER_REAG_COST:
1✔
883
    return new BLong( lower_reagent_cost().sum() );
1✔
884
    break;
885
  case MBR_SPELL_DAMAGE_INCREASE:
1✔
886
    return new BLong( spell_damage_increase().sum() );
1✔
887
    break;
888
  case MBR_FASTER_CASTING:
1✔
889
    return new BLong( faster_casting().sum() );
1✔
890
    break;
891
  case MBR_FASTER_CAST_RECOVERY:
1✔
892
    return new BLong( faster_cast_recovery().sum() );
1✔
893
    break;
894
  case MBR_DEFENCE_CHANCE_INCREASE:
1✔
895
    return new BLong( defence_increase().sum() );
1✔
896
    break;
897
  case MBR_DEFENCE_CHANCE_INCREASE_CAP:
1✔
898
    return new BLong( defence_increase_cap().sum() );
1✔
899
    break;
900
  case MBR_LOWER_MANA_COST:
1✔
901
    return new BLong( lower_mana_cost().sum() );
1✔
902
    break;
903
  case MBR_HIT_CHANCE:
1✔
904
    return new BLong( hit_chance().sum() );
1✔
905
    break;
906
  case MBR_FIRE_RESIST_CAP:
1✔
907
    return new BLong( fire_resist_cap().sum() );
1✔
908
    break;
909
  case MBR_COLD_RESIST_CAP:
1✔
910
    return new BLong( cold_resist_cap().sum() );
1✔
911
    break;
912
  case MBR_ENERGY_RESIST_CAP:
1✔
913
    return new BLong( energy_resist_cap().sum() );
1✔
914
    break;
915
  case MBR_POISON_RESIST_CAP:
1✔
916
    return new BLong( poison_resist_cap().sum() );
1✔
917
    break;
918
  case MBR_PHYSICAL_RESIST_CAP:
1✔
919
    return new BLong( physical_resist_cap().sum() );
1✔
920
    break;
921
  case MBR_LUCK:
1✔
922
    return new BLong( luck().sum() );
1✔
923
    break;
924
  case MBR_SWING_SPEED_INCREASE:
1✔
925
    return new BLong( swing_speed_increase().sum() );
1✔
926
    break;
927
  case MBR_MIN_ATTACK_RANGE_INCREASE:
1✔
928
    return new BLong( min_attack_range_increase().sum() );
1✔
929
    break;
930
  case MBR_MAX_ATTACK_RANGE_INCREASE:
1✔
931
    return new BLong( max_attack_range_increase().sum() );
1✔
932
    break;
933
  case MBR_FIRE_RESIST_MOD:
1✔
934
    return new BLong( fire_resist().mod );
1✔
935
    break;
936
  case MBR_COLD_RESIST_MOD:
1✔
937
    return new BLong( cold_resist().mod );
1✔
938
    break;
939
  case MBR_ENERGY_RESIST_MOD:
1✔
940
    return new BLong( energy_resist().mod );
1✔
941
    break;
942
  case MBR_POISON_RESIST_MOD:
1✔
943
    return new BLong( poison_resist().mod );
1✔
944
    break;
945
  case MBR_PHYSICAL_RESIST_MOD:
1✔
946
    return new BLong( physical_resist().mod );
1✔
947
    break;
948
  case MBR_FIRE_DAMAGE:
1✔
949
    return new BLong( fire_damage().sum() );
1✔
950
    break;
951
  case MBR_COLD_DAMAGE:
1✔
952
    return new BLong( cold_damage().sum() );
1✔
953
    break;
954
  case MBR_ENERGY_DAMAGE:
1✔
955
    return new BLong( energy_damage().sum() );
1✔
956
    break;
957
  case MBR_POISON_DAMAGE:
1✔
958
    return new BLong( poison_damage().sum() );
1✔
959
    break;
960
  case MBR_PHYSICAL_DAMAGE:
1✔
961
    return new BLong( physical_damage().sum() );
1✔
962
    break;
963
  case MBR_FIRE_DAMAGE_MOD:
1✔
964
    return new BLong( fire_damage().mod );
1✔
965
    break;
966
  case MBR_COLD_DAMAGE_MOD:
1✔
967
    return new BLong( cold_damage().mod );
1✔
968
    break;
969
  case MBR_ENERGY_DAMAGE_MOD:
1✔
970
    return new BLong( energy_damage().mod );
1✔
971
    break;
972
  case MBR_POISON_DAMAGE_MOD:
1✔
973
    return new BLong( poison_damage().mod );
1✔
974
    break;
975
  case MBR_PHYSICAL_DAMAGE_MOD:
1✔
976
    return new BLong( physical_damage().mod );
1✔
977
    break;
978
  case MBR_LOWER_REAG_COST_MOD:
1✔
979
    return new BLong( lower_reagent_cost().mod );
1✔
980
    break;
981
  case MBR_SPELL_DAMAGE_INCREASE_MOD:
1✔
982
    return new BLong( spell_damage_increase().mod );
1✔
983
    break;
984
  case MBR_FASTER_CASTING_MOD:
1✔
985
    return new BLong( faster_casting().mod );
1✔
986
    break;
987
  case MBR_FASTER_CAST_RECOVERY_MOD:
1✔
988
    return new BLong( faster_cast_recovery().mod );
1✔
989
    break;
990
  case MBR_DEFENCE_CHANCE_INCREASE_MOD:
1✔
991
    return new BLong( defence_increase().mod );
1✔
992
    break;
993
  case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
1✔
994
    return new BLong( defence_increase_cap().mod );
1✔
995
    break;
996
  case MBR_LOWER_MANA_COST_MOD:
1✔
997
    return new BLong( lower_mana_cost().mod );
1✔
998
    break;
999
  case MBR_HIT_CHANCE_MOD:
1✔
1000
    return new BLong( hit_chance().mod );
1✔
1001
    break;
1002
  case MBR_FIRE_RESIST_CAP_MOD:
1✔
1003
    return new BLong( fire_resist_cap().mod );
1✔
1004
    break;
1005
  case MBR_COLD_RESIST_CAP_MOD:
1✔
1006
    return new BLong( cold_resist_cap().mod );
1✔
1007
    break;
1008
  case MBR_ENERGY_RESIST_CAP_MOD:
1✔
1009
    return new BLong( energy_resist_cap().mod );
1✔
1010
    break;
1011
  case MBR_POISON_RESIST_CAP_MOD:
1✔
1012
    return new BLong( poison_resist_cap().mod );
1✔
1013
    break;
1014
  case MBR_PHYSICAL_RESIST_CAP_MOD:
1✔
1015
    return new BLong( physical_resist_cap().mod );
1✔
1016
    break;
1017
  case MBR_LUCK_MOD:
1✔
1018
    return new BLong( luck().mod );
1✔
1019
    break;
1020
  case MBR_SWING_SPEED_INCREASE_MOD:
1✔
1021
    return new BLong( swing_speed_increase().mod );
1✔
1022
    break;
1023
  case MBR_MIN_ATTACK_RANGE_INCREASE_MOD:
1✔
1024
    return new BLong( min_attack_range_increase().mod );
1✔
1025
    break;
1026
  case MBR_MAX_ATTACK_RANGE_INCREASE_MOD:
1✔
1027
    return new BLong( max_attack_range_increase().mod );
1✔
1028
    break;
1029

1030
  case MBR_GETGOTTENBY:
×
1031
    if ( has_gotten_by() )
×
1032
      return new Module::ECharacterRefObjImp( gotten_by() );
×
1033
    return new BError( "Gotten By nullptr" );
×
1034
    break;
1035
  case MBR_PROCESS:
4✔
1036
  {
1037
    Module::UOExecutorModule* proc = process();
4✔
1038
    if ( proc )
4✔
1039
    {
1040
      Core::UOExecutor* executor = static_cast<Core::UOExecutor*>( &proc->exec );
3✔
1041
      return new Core::ScriptExObjImp( executor );
3✔
1042
    }
1043
    return new BError( "No script running" );
1✔
1044
    break;
1045
  }
1046
  case MBR_DOUBLECLICKRANGE:
×
1047
  {
1048
    const ItemDesc& itemdesc = this->itemdesc();
×
1049
    return new BLong( itemdesc.doubleclick_range );
×
1050
    break;
1051
  }
1052
  case MBR_QUALITY:
1✔
1053
    return new Double( quality() );
1✔
1054
    break;
1055
  case MBR_HP:
5✔
1056
    return new BLong( hp_ );
5✔
1057
    break;
1058
  case MBR_MAXHP_MOD:
1✔
1059
    return new BLong( maxhp_mod() );
1✔
1060
    break;
1061
  case MBR_MAXHP:
×
1062
    return new BLong( Clib::clamp_convert<s32>( maxhp() * quality() ) );
×
1063
    break;
1064
  case MBR_NAME_SUFFIX:
1✔
1065
    return new String( name_suffix() );
1✔
1066
    break;
1067
  case MBR_HOUSE:
×
1068
    if ( house() != nullptr )
×
1069
      return house()->make_ref();
×
1070
    return new BError( "This is a not component of any house" );
×
1071
    break;
1072
  case MBR_NO_DROP:
2✔
1073
    return new BLong( no_drop() );
2✔
1074
  case MBR_CHARACTER_OWNER:
3✔
1075
  {
1076
    Mobile::Character* owner = GetCharacterOwner();
3✔
1077
    if ( owner != nullptr )
3✔
1078
    {
1079
      return new Module::EOfflineCharacterRefObjImp( owner );
3✔
1080
    }
1081
    return new BError( "This item is not owned by any character" );
×
1082
    break;
1083
  }
1084
  case MBR_WEIGHT_MULTIPLIER_MOD:
1✔
1085
    return new Double( weight_multiplier_mod() );
1✔
1086
    break;
1087
  default:
123✔
1088
    return nullptr;
123✔
1089
  }
1090
}
1091

1092
BObjectImp* Item::get_script_member( const char* membername ) const
77✔
1093
{
1094
  ObjMember* objmember = getKnownObjMember( membername );
77✔
1095
  if ( objmember != nullptr )
77✔
1096
    return this->get_script_member_id( objmember->id );
77✔
1097
  return nullptr;
×
1098
}
1099

1100
BObjectImp* Item::set_script_member_id( const int id, const std::string& value )
21✔
1101
{
1102
  BObjectImp* imp = base::set_script_member_id( id, value );
21✔
1103
  if ( imp != nullptr )
21✔
1104
    return imp;
14✔
1105

1106
  switch ( id )
7✔
1107
  {
1108
  case MBR_USESCRIPT:
1✔
1109
    on_use_script_ = value;
1✔
1110
    return new String( value );
1✔
1111
  case MBR_SNOOPSCRIPT:
1✔
1112
    snoop_script_ = value;
1✔
1113
    return new String( value );
1✔
1114
  case MBR_EQUIPSCRIPT:
1✔
1115
    equip_script_ = value;
1✔
1116
    return new String( value );
1✔
1117
  case MBR_UNEQUIPSCRIPT:
1✔
1118
    unequip_script_ = value;
1✔
1119
    return new String( value );
1✔
1120
  case MBR_NAME_SUFFIX:
1✔
1121
    set_dirty();
1✔
1122
    increv();
1✔
1123
    send_object_cache_to_inrange( this );
1✔
1124
    name_suffix( value );
1✔
1125
    return new String( value );
1✔
1126

1127
  default:
2✔
1128
    return nullptr;
2✔
1129
  }
1130
}
1131

1132
BObjectImp* Item::set_script_member( const char* membername, const std::string& value )
7✔
1133
{
1134
  ObjMember* objmember = getKnownObjMember( membername );
7✔
1135
  if ( objmember != nullptr )
7✔
1136
    return this->set_script_member_id( objmember->id, value );
7✔
1137
  return nullptr;
×
1138
}
1139

1140
BObjectImp* Item::set_script_member_id( const int id, int value )
137✔
1141
{
1142
  BObjectImp* imp = base::set_script_member_id( id, value );
137✔
1143
  if ( imp != nullptr )
137✔
1144
    return imp;
2✔
1145

1146
  switch ( id )
135✔
1147
  {
1148
  case MBR_MOVABLE:
15✔
1149
    restart_decay_timer();
15✔
1150
    movable( value ? true : false );
15✔
1151
    increv();
15✔
1152
    return new BLong( movable() );
15✔
1153
  case MBR_INVISIBLE:
2✔
1154
    restart_decay_timer();
2✔
1155
    invisible( value ? true : false );
2✔
1156
    increv();
2✔
1157
    return new BLong( invisible() );
2✔
1158
  case MBR_CURSED:
1✔
1159
    restart_decay_timer();
1✔
1160
    cursed( value ? true : false );
1✔
1161
    increv();
1✔
1162
    return new BLong( cursed() );
1✔
1163
  case MBR_DECAYAT:
1✔
1164
    decayat_gameclock_ = value;
1✔
1165
    return new BLong( decayat_gameclock_ );
1✔
1166
  case MBR_SELLPRICE:
1✔
1167
    sellprice( value );
1✔
1168
    return new BLong( value );
1✔
1169
  case MBR_BUYPRICE:
1✔
1170
    buyprice( value );
1✔
1171
    return new BLong( value );
1✔
1172
  case MBR_NEWBIE:
1✔
1173
    restart_decay_timer();
1✔
1174
    newbie( value ? true : false );
1✔
1175
    increv();
1✔
1176
    return new BLong( newbie() );
1✔
1177
  case MBR_INSURED:
1✔
1178
    restart_decay_timer();
1✔
1179
    insured( value ? true : false );
1✔
1180
    increv();
1✔
1181
    return new BLong( insured() );
1✔
1182
  case MBR_FACING:
1✔
1183
    setfacing( (u8)value );
1✔
1184
    return new BLong( facing );
1✔
1185
  case MBR_SAVEONEXIT:
×
1186
    saveonexit( value ? true : false );
×
1187
    return new BLong( saveonexit() );
×
1188
  case MBR_FIRE_RESIST_MOD:
3✔
1189
    fire_resist( fire_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1190
    if ( container != nullptr )
3✔
1191
    {
1192
      if ( Core::IsCharacter( container->serial ) )
2✔
1193
      {
1194
        Mobile::Character* chr = container->get_chr_owner();
2✔
1195
        if ( chr != nullptr )
2✔
1196
          chr->refresh_ar();
2✔
1197
      }
1198
    }
1199
    return new BLong( fire_resist().mod );
3✔
1200
    break;
1201
  case MBR_COLD_RESIST_MOD:
3✔
1202
    cold_resist( cold_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1203
    if ( container != nullptr )
3✔
1204
    {
1205
      if ( Core::IsCharacter( container->serial ) )
2✔
1206
      {
1207
        Mobile::Character* chr = container->get_chr_owner();
2✔
1208
        if ( chr != nullptr )
2✔
1209
          chr->refresh_ar();
2✔
1210
      }
1211
    }
1212
    return new BLong( cold_resist().mod );
3✔
1213
    break;
1214
  case MBR_ENERGY_RESIST_MOD:
3✔
1215
    energy_resist( energy_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1216
    if ( container != nullptr )
3✔
1217
    {
1218
      if ( Core::IsCharacter( container->serial ) )
2✔
1219
      {
1220
        Mobile::Character* chr = container->get_chr_owner();
2✔
1221
        if ( chr != nullptr )
2✔
1222
          chr->refresh_ar();
2✔
1223
      }
1224
    }
1225
    return new BLong( energy_resist().mod );
3✔
1226
    break;
1227
  case MBR_POISON_RESIST_MOD:
3✔
1228
    poison_resist( poison_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1229
    if ( container != nullptr )
3✔
1230
    {
1231
      if ( Core::IsCharacter( container->serial ) )
2✔
1232
      {
1233
        Mobile::Character* chr = container->get_chr_owner();
2✔
1234
        if ( chr != nullptr )
2✔
1235
          chr->refresh_ar();
2✔
1236
      }
1237
    }
1238
    return new BLong( poison_resist().mod );
3✔
1239
    break;
1240
  case MBR_PHYSICAL_RESIST_MOD:
3✔
1241
    physical_resist( physical_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1242
    if ( container != nullptr )
3✔
1243
    {
1244
      if ( Core::IsCharacter( container->serial ) )
2✔
1245
      {
1246
        Mobile::Character* chr = container->get_chr_owner();
2✔
1247
        if ( chr != nullptr )
2✔
1248
          chr->refresh_ar();
2✔
1249
      }
1250
    }
1251
    return new BLong( physical_resist().mod );
3✔
1252
    break;
1253
  case MBR_FIRE_RESIST_CAP_MOD:
2✔
1254
    fire_resist_cap( fire_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
1255
    if ( container != nullptr )
2✔
1256
    {
1257
      if ( Core::IsCharacter( container->serial ) )
1✔
1258
      {
1259
        Mobile::Character* chr = container->get_chr_owner();
1✔
1260
        if ( chr != nullptr )
1✔
1261
          chr->refresh_ar();
1✔
1262
      }
1263
    }
1264
    return new BLong( fire_resist_cap().mod );
2✔
1265
    break;
1266
  case MBR_COLD_RESIST_CAP_MOD:
2✔
1267
    cold_resist_cap( cold_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
1268
    if ( container != nullptr )
2✔
1269
    {
1270
      if ( Core::IsCharacter( container->serial ) )
1✔
1271
      {
1272
        Mobile::Character* chr = container->get_chr_owner();
1✔
1273
        if ( chr != nullptr )
1✔
1274
          chr->refresh_ar();
1✔
1275
      }
1276
    }
1277
    return new BLong( cold_resist_cap().mod );
2✔
1278
    break;
1279
  case MBR_ENERGY_RESIST_CAP_MOD:
2✔
1280
    energy_resist_cap( energy_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
1281
    if ( container != nullptr )
2✔
1282
    {
1283
      if ( Core::IsCharacter( container->serial ) )
1✔
1284
      {
1285
        Mobile::Character* chr = container->get_chr_owner();
1✔
1286
        if ( chr != nullptr )
1✔
1287
          chr->refresh_ar();
1✔
1288
      }
1289
    }
1290
    return new BLong( energy_resist_cap().mod );
2✔
1291
    break;
1292
  case MBR_POISON_RESIST_CAP_MOD:
2✔
1293
    poison_resist_cap( poison_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
1294
    if ( container != nullptr )
2✔
1295
    {
1296
      if ( Core::IsCharacter( container->serial ) )
1✔
1297
      {
1298
        Mobile::Character* chr = container->get_chr_owner();
1✔
1299
        if ( chr != nullptr )
1✔
1300
          chr->refresh_ar();
1✔
1301
      }
1302
    }
1303
    return new BLong( poison_resist_cap().mod );
2✔
1304
    break;
1305
  case MBR_PHYSICAL_RESIST_CAP_MOD:
2✔
1306
    physical_resist_cap( physical_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
1307
    if ( container != nullptr )
2✔
1308
    {
1309
      if ( Core::IsCharacter( container->serial ) )
1✔
1310
      {
1311
        Mobile::Character* chr = container->get_chr_owner();
1✔
1312
        if ( chr != nullptr )
1✔
1313
          chr->refresh_ar();
1✔
1314
      }
1315
    }
1316
    return new BLong( physical_resist_cap().mod );
2✔
1317
    break;
1318

1319
  case MBR_FIRE_DAMAGE_MOD:
3✔
1320
    fire_damage( fire_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1321
    if ( container != nullptr )
3✔
1322
    {
1323
      if ( Core::IsCharacter( container->serial ) )
2✔
1324
      {
1325
        Mobile::Character* chr = container->get_chr_owner();
2✔
1326
        if ( chr != nullptr )
2✔
1327
          chr->refresh_ar();
2✔
1328
      }
1329
    }
1330
    return new BLong( fire_damage().mod );
3✔
1331
    break;
1332
  case MBR_COLD_DAMAGE_MOD:
3✔
1333
    cold_damage( cold_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1334
    if ( container != nullptr )
3✔
1335
    {
1336
      if ( Core::IsCharacter( container->serial ) )
2✔
1337
      {
1338
        Mobile::Character* chr = container->get_chr_owner();
2✔
1339
        if ( chr != nullptr )
2✔
1340
          chr->refresh_ar();
2✔
1341
      }
1342
    }
1343
    return new BLong( cold_damage().mod );
3✔
1344
    break;
1345
  case MBR_ENERGY_DAMAGE_MOD:
3✔
1346
    energy_damage( energy_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1347
    if ( container != nullptr )
3✔
1348
    {
1349
      if ( Core::IsCharacter( container->serial ) )
2✔
1350
      {
1351
        Mobile::Character* chr = container->get_chr_owner();
2✔
1352
        if ( chr != nullptr )
2✔
1353
          chr->refresh_ar();
2✔
1354
      }
1355
    }
1356
    return new BLong( energy_damage().mod );
3✔
1357
    break;
1358
  case MBR_POISON_DAMAGE_MOD:
3✔
1359
    poison_damage( poison_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1360
    if ( container != nullptr )
3✔
1361
    {
1362
      if ( Core::IsCharacter( container->serial ) )
2✔
1363
      {
1364
        Mobile::Character* chr = container->get_chr_owner();
2✔
1365
        if ( chr != nullptr )
2✔
1366
          chr->refresh_ar();
2✔
1367
      }
1368
    }
1369
    return new BLong( poison_damage().mod );
3✔
1370
    break;
1371

1372
  case MBR_PHYSICAL_DAMAGE_MOD:
3✔
1373
    physical_damage( physical_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1374
    if ( container != nullptr )
3✔
1375
    {
1376
      if ( Core::IsCharacter( container->serial ) )
2✔
1377
      {
1378
        Mobile::Character* chr = container->get_chr_owner();
2✔
1379
        if ( chr != nullptr )
2✔
1380
          chr->refresh_ar();
2✔
1381
      }
1382
    }
1383
    return new BLong( physical_damage().mod );
3✔
1384
    break;
1385

1386
  case MBR_LOWER_REAG_COST_MOD:
3✔
1387
    lower_reagent_cost( lower_reagent_cost().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1388
    if ( container != nullptr )
3✔
1389
    {
1390
      if ( Core::IsCharacter( container->serial ) )
2✔
1391
      {
1392
        Mobile::Character* chr = container->get_chr_owner();
2✔
1393
        if ( chr != nullptr )
2✔
1394
          chr->refresh_ar();
2✔
1395
      }
1396
    }
1397
    return new BLong( lower_reagent_cost().mod );
3✔
1398
    break;
1399
  case MBR_SPELL_DAMAGE_INCREASE_MOD:
3✔
1400
    spell_damage_increase( spell_damage_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1401
    if ( container != nullptr )
3✔
1402
    {
1403
      if ( Core::IsCharacter( container->serial ) )
2✔
1404
      {
1405
        Mobile::Character* chr = container->get_chr_owner();
2✔
1406
        if ( chr != nullptr )
2✔
1407
          chr->refresh_ar();
2✔
1408
      }
1409
    }
1410
    return new BLong( spell_damage_increase().mod );
3✔
1411
    break;
1412
  case MBR_FASTER_CASTING_MOD:
3✔
1413
    faster_casting( faster_casting().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1414
    if ( container != nullptr )
3✔
1415
    {
1416
      if ( Core::IsCharacter( container->serial ) )
2✔
1417
      {
1418
        Mobile::Character* chr = container->get_chr_owner();
2✔
1419
        if ( chr != nullptr )
2✔
1420
          chr->refresh_ar();
2✔
1421
      }
1422
    }
1423
    return new BLong( faster_casting().mod );
3✔
1424
    break;
1425
  case MBR_FASTER_CAST_RECOVERY_MOD:
3✔
1426
    faster_cast_recovery( faster_cast_recovery().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1427
    if ( container != nullptr )
3✔
1428
    {
1429
      if ( Core::IsCharacter( container->serial ) )
2✔
1430
      {
1431
        Mobile::Character* chr = container->get_chr_owner();
2✔
1432
        if ( chr != nullptr )
2✔
1433
          chr->refresh_ar();
2✔
1434
      }
1435
    }
1436
    return new BLong( faster_cast_recovery().mod );
3✔
1437
    break;
1438
  case MBR_DEFENCE_CHANCE_INCREASE_MOD:
3✔
1439
    defence_increase( defence_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1440
    if ( container != nullptr )
3✔
1441
    {
1442
      if ( Core::IsCharacter( container->serial ) )
2✔
1443
      {
1444
        Mobile::Character* chr = container->get_chr_owner();
2✔
1445
        if ( chr != nullptr )
2✔
1446
          chr->refresh_ar();
2✔
1447
      }
1448
    }
1449
    return new BLong( defence_increase().mod );
3✔
1450
    break;
1451
  case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
2✔
1452
    defence_increase_cap( defence_increase_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
1453
    if ( container != nullptr )
2✔
1454
    {
1455
      if ( Core::IsCharacter( container->serial ) )
1✔
1456
      {
1457
        Mobile::Character* chr = container->get_chr_owner();
1✔
1458
        if ( chr != nullptr )
1✔
1459
          chr->refresh_ar();
1✔
1460
      }
1461
    }
1462
    return new BLong( defence_increase_cap().mod );
2✔
1463
    break;
1464
  case MBR_LOWER_MANA_COST_MOD:
3✔
1465
    lower_mana_cost( lower_mana_cost().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1466
    if ( container != nullptr )
3✔
1467
    {
1468
      if ( Core::IsCharacter( container->serial ) )
2✔
1469
      {
1470
        Mobile::Character* chr = container->get_chr_owner();
2✔
1471
        if ( chr != nullptr )
2✔
1472
          chr->refresh_ar();
2✔
1473
      }
1474
    }
1475
    return new BLong( lower_mana_cost().mod );
3✔
1476
    break;
1477
  case MBR_HITCHANCE_MOD:  // to be made redundant in the future
3✔
1478
  case MBR_HIT_CHANCE_MOD:
1479
    hit_chance( hit_chance().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1480
    if ( container != nullptr )
3✔
1481
    {
1482
      if ( Core::IsCharacter( container->serial ) )
2✔
1483
      {
1484
        Mobile::Character* chr = container->get_chr_owner();
2✔
1485
        if ( chr != nullptr )
2✔
1486
          chr->refresh_ar();
2✔
1487
      }
1488
    }
1489
    return new BLong( hit_chance().mod );
3✔
1490
    break;
1491
  case MBR_LUCK_MOD:
3✔
1492
    luck( luck().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1493
    if ( container != nullptr )
3✔
1494
    {
1495
      if ( Core::IsCharacter( container->serial ) )
2✔
1496
      {
1497
        Mobile::Character* chr = container->get_chr_owner();
2✔
1498
        if ( chr != nullptr )
2✔
1499
          chr->refresh_ar();
2✔
1500
      }
1501
    }
1502
    return new BLong( luck().mod );
3✔
1503
    break;
1504
  case MBR_SWING_SPEED_INCREASE_MOD:
3✔
1505
    swing_speed_increase( swing_speed_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1506
    if ( container != nullptr )
3✔
1507
    {
1508
      if ( Core::IsCharacter( container->serial ) )
2✔
1509
      {
1510
        Mobile::Character* chr = container->get_chr_owner();
2✔
1511
        if ( chr != nullptr )
2✔
1512
          chr->refresh_ar();
2✔
1513
      }
1514
    }
1515
    return new BLong( swing_speed_increase().mod );
3✔
1516
    break;
1517
  case MBR_MIN_ATTACK_RANGE_INCREASE_MOD:
3✔
1518
    min_attack_range_increase(
6✔
1519
        min_attack_range_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1520
    if ( container != nullptr )
3✔
1521
    {
1522
      if ( Core::IsCharacter( container->serial ) )
2✔
1523
      {
1524
        Mobile::Character* chr = container->get_chr_owner();
2✔
1525
        if ( chr != nullptr )
2✔
1526
          chr->refresh_ar();
2✔
1527
      }
1528
    }
1529
    return new BLong( min_attack_range_increase().mod );
3✔
1530
    break;
1531
  case MBR_MAX_ATTACK_RANGE_INCREASE_MOD:
3✔
1532
    max_attack_range_increase(
6✔
1533
        max_attack_range_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
1534
    if ( container != nullptr )
3✔
1535
    {
1536
      if ( Core::IsCharacter( container->serial ) )
2✔
1537
      {
1538
        Mobile::Character* chr = container->get_chr_owner();
2✔
1539
        if ( chr != nullptr )
2✔
1540
          chr->refresh_ar();
2✔
1541
      }
1542
    }
1543
    return new BLong( max_attack_range_increase().mod );
3✔
1544
    break;
1545

1546
  case MBR_QUALITY:
×
1547
    quality( double( value ) );
×
1548
    return new Double( double( value ) );
×
1549
    break;
1550
  case MBR_HP:
5✔
1551
    hp_ = Clib::clamp_convert<u16>( value );
5✔
1552

1553
    if ( this->isa( Core::UOBJ_CLASS::CLASS_ARMOR ) )
5✔
1554
    {
1555
      if ( container != nullptr )
×
1556
      {
1557
        if ( Core::IsCharacter( container->serial ) )
×
1558
        {
1559
          Mobile::Character* chr = container->get_chr_owner();
×
1560
          if ( chr != nullptr )
×
1561
            chr->refresh_ar();
×
1562
        }
1563
      }
1564
    }
1565
    send_hit_status_inrange();
5✔
1566
    return new BLong( hp_ );
5✔
1567
  case MBR_MAXHP_MOD:
1✔
1568
    this->maxhp_mod( Clib::clamp_convert<s16>( value ) );
1✔
1569
    if ( this->isa( Core::UOBJ_CLASS::CLASS_ARMOR ) )
1✔
1570
    {
1571
      if ( container != nullptr )
×
1572
      {
1573
        if ( Core::IsCharacter( container->serial ) )
×
1574
        {
1575
          Mobile::Character* chr = container->get_chr_owner();
×
1576
          if ( chr != nullptr )
×
1577
            chr->refresh_ar();
×
1578
        }
1579
      }
1580
    }
1581
    send_hit_status_inrange();
1✔
1582
    return new BLong( value );
1✔
1583
  case MBR_NO_DROP:
3✔
1584
    no_drop( value ? true : false );
3✔
1585
    return new BLong( no_drop() );
3✔
1586
  case MBR_WEIGHT_MULTIPLIER_MOD:
2✔
1587
    return set_script_member_id_double( id, value );
2✔
1588
  default:
25✔
1589
    return nullptr;
25✔
1590
  }
1591
}
1592

1593
BObjectImp* Item::set_script_member( const char* membername, int value )
42✔
1594
{
1595
  ObjMember* objmember = getKnownObjMember( membername );
42✔
1596
  if ( objmember != nullptr )
42✔
1597
    return this->set_script_member_id( objmember->id, value );
42✔
1598
  return nullptr;
×
1599
}
1600

1601
BObjectImp* Item::set_script_member_id_double( const int id, double value )
19✔
1602
{
1603
  BObjectImp* imp = base::set_script_member_id_double( id, value );
19✔
1604
  if ( imp != nullptr )
19✔
1605
    return imp;
×
1606
  switch ( id )
19✔
1607
  {
1608
  case MBR_QUALITY:
1✔
1609
    quality( value );
1✔
1610
    return new Double( value );
1✔
1611
  case MBR_WEIGHT_MULTIPLIER_MOD:
5✔
1612
  {
1613
    if ( value < 0.0 )
5✔
1614
    {
1615
      return new BError( "weight_multiplier_mod cannot be less than 0.0" );
×
1616
    }
1617

1618
    if ( container )
5✔
1619
    {
1620
      int old_weight = weight();
2✔
1621
      weight_multiplier_mod( value );
2✔
1622
      int new_weight = weight();
2✔
1623
      int weight_delta = new_weight - old_weight;
2✔
1624
      container->add_bulk( 0, weight_delta );
2✔
1625
    }
1626
    else
1627
    {
1628
      weight_multiplier_mod( value );
3✔
1629
    }
1630

1631
    increv_send_object_recursive();
5✔
1632

1633
    UpdateCharacterWeight( this );
5✔
1634
    return new Double( weight_multiplier_mod() );
5✔
1635
    break;
1636
  }
1637
  default:
13✔
1638
    return nullptr;
13✔
1639
  }
1640
}
1641

1642
BObjectImp* Item::set_script_member_double( const char* membername, double value )
2✔
1643
{
1644
  ObjMember* objmember = getKnownObjMember( membername );
2✔
1645
  if ( objmember != nullptr )
2✔
1646
    return this->set_script_member_id_double( objmember->id, value );
2✔
1647
  return nullptr;
×
1648
}
1649

1650
BObjectImp* Item::script_method_id( const int id, Core::UOExecutor& ex )
284✔
1651
{
1652
  BObjectImp* imp = base::script_method_id( id, ex );
284✔
1653
  if ( imp != nullptr )
284✔
1654
    return imp;
251✔
1655
  switch ( id )
33✔
1656
  {
1657
  case MTH_SPLITSTACK_AT:
×
1658
  {
1659
    unsigned short amt;
1660
    Core::Pos4d newpos;
×
1661
    Item* new_stack( nullptr );
×
1662
    u16 item_amount = this->getamount();
×
1663

1664
    if ( !ex.hasParams( 5 ) )
×
1665
      return new BError( "Not enough parameters" );
×
1666
    if ( !ex.getPos4dParam( 0, 1, 2, 3, &newpos ) )
×
1667
      return new BError( "Invalid parameter type" );
×
1668
    if ( !ex.getParam( 4, amt ) )
×
1669
      return new BError( "No amount specified to pull from existing stack" );
×
1670
    if ( amt > this->getamount() )
×
1671
      return new BError( "Amount must be less than or equal to the stack amount" );
×
1672
    if ( amt < 1 )
×
1673
      return new BError( "Amount was less than 1" );
×
1674
    if ( this->inuse() )
×
1675
      return new BError( "Item is in use" );
×
1676

1677
    // Check first if the item is non-stackable and just force stacked with CreateItemInInventory
1678
    if ( !this->stackable() && amt > 1 )
×
1679
    {
1680
      unsigned short i;
1681

1682
      for ( i = 1; i <= amt; i++ )
×
1683
      {
1684
        if ( this->getamount() == 1 )
×
1685
          new_stack = this->clone();
×
1686
        else
1687
          new_stack = this->remove_part_of_stack( 1 );
×
1688
        new_stack->setposition( newpos );
×
1689
        add_item_to_world( new_stack );
×
1690
        move_item( new_stack, newpos );
×
1691
        update_item_to_inrange( new_stack );
×
1692
      }
1693

1694
      if ( this->getamount() == 1 )
×
1695
        destroy_item( this );
×
1696
      else
1697
        update_item_to_inrange( this );
×
1698
      if ( new_stack != nullptr )
×
1699
        return new Module::EItemRefObjImp( new_stack );
×
1700
      return nullptr;
×
1701
    }
1702

1703

1704
    if ( amt == this->getamount() )
×
1705
      new_stack = this->clone();
×
1706
    else
1707
      new_stack = this->remove_part_of_stack( amt );
×
1708

1709
    new_stack->setposition( newpos );
×
1710
    new_stack->setamount( amt );
×
1711
    add_item_to_world( new_stack );
×
1712
    move_item( new_stack, newpos );
×
1713
    update_item_to_inrange( new_stack );
×
1714

1715
    if ( amt == item_amount )
×
1716
      destroy_item( this );
×
1717
    else
1718
      update_item_to_inrange( this );
×
1719

1720
    return new Module::EItemRefObjImp( new_stack );
×
1721

1722
    break;
1723
  }
1724
  case MTH_SPLITSTACK_INTO:
1✔
1725
  {
1726
    unsigned short amt;
1727
    Item* cont_item;
1728

1729
    if ( !ex.hasParams( 2 ) )
1✔
1730
      return new BError( "Not enough parameters" );
×
1731
    if ( !ex.getItemParam( 0, cont_item ) )
1✔
1732
      return new BError( "No container specified" );
×
1733
    if ( !ex.getParam( 1, amt ) )
1✔
1734
      return new BError( "No amount specified to pull from existing stack" );
×
1735
    if ( amt > this->getamount() )
1✔
1736
      return new BError( "Amount must be less than or equal to stack amount" );
×
1737
    if ( amt < 1 )
1✔
1738
      return new BError( "Amount was less than 1" );
×
1739
    if ( this->inuse() )
1✔
1740
      return new BError( "Item is in use" );
×
1741
    if ( !cont_item->isa( Core::UOBJ_CLASS::CLASS_CONTAINER ) )
1✔
1742
      return new BError( "Non-container selected as target" );
×
1743

1744
    Core::UContainer* newcontainer = static_cast<Core::UContainer*>( cont_item );
1✔
1745

1746
    // Check first if the item is non-stackable and just force stacked with CreateItemInInventory
1747

1748
    Item* new_stack( nullptr );
1✔
1749
    u16 item_amount = this->getamount();
1✔
1750

1751
    if ( !this->stackable() && amt > 1 )
1✔
1752
    {
1753
      for ( unsigned short i = 1; i <= amt; i++ )
×
1754
      {
1755
        if ( this->getamount() == 1 )
×
1756
          new_stack = this->clone();
×
1757
        else
1758
          new_stack = this->remove_part_of_stack( 1 );
×
1759

1760
        bool can_insert = newcontainer->can_insert_add_item(
×
1761
            nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
1762
        if ( !can_insert )
×
1763
        {
1764
          // Put new_stack back with the original stack
1765
          if ( new_stack != this )
×
1766
            this->add_to_self( new_stack );
×
1767
          return new BError( "Could not insert new stack into container" );
×
1768
        }
1769

1770
        newcontainer->add_at_random_location( new_stack );
×
1771
        update_item_to_inrange( new_stack );
×
1772
        UpdateCharacterWeight( new_stack );
×
1773
        newcontainer->on_insert_add_item( nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
×
1774
      }
1775

1776
      if ( this->getamount() == 1 )
×
1777
        destroy_item( this );
×
1778
      else
1779
        update_item_to_inrange( this );
×
1780
      if ( new_stack != nullptr )
×
1781
        return new Module::EItemRefObjImp( new_stack );
×
1782
      return nullptr;
×
1783
    }
1784

1785
    if ( amt == this->getamount() )
1✔
1786
      new_stack = this->clone();
×
1787
    else
1788
      new_stack = this->remove_part_of_stack( amt );
1✔
1789

1790
    auto create_new_stack = [&]() -> BObjectImp*
1✔
1791
    {
1792
      bool can_insert =
1793
          newcontainer->can_insert_add_item( nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
1✔
1794
      if ( !can_insert )
1✔
1795
      {
1796
        // Put newstack back with the original stack
1797
        if ( new_stack != this )
×
1798
          this->add_to_self( new_stack );
×
1799
        return new BError( "Could not insert new stack into container" );
×
1800
      }
1801
      newcontainer->add_at_random_location( new_stack );
1✔
1802
      new_stack->setamount( amt );
1✔
1803
      update_item_to_inrange( new_stack );
1✔
1804
      UpdateCharacterWeight( new_stack );
1✔
1805
      newcontainer->on_insert_add_item( nullptr, Core::UContainer::MT_CORE_MOVED, new_stack );
1✔
1806

1807
      if ( amt == item_amount )
1✔
1808
        destroy_item( this );
×
1809
      else
1810
        update_item_to_inrange( this );
1✔
1811

1812
      return new Module::EItemRefObjImp( new_stack );
1✔
1813
    };
1✔
1814

1815
    int add_to_existing_stack;
1816
    if ( !ex.hasParams( 3 ) ||
1✔
1817
         ( ex.getParam( 2, add_to_existing_stack ) && add_to_existing_stack != 0 ) )
×
1818
    {
1819
      Item* existing_stack = newcontainer->find_addable_stack( new_stack );
1✔
1820
      if ( existing_stack != nullptr && new_stack->stackable() )
1✔
1821
      {
1822
        if ( !newcontainer->can_insert_increase_stack( nullptr, Core::UContainer::MT_CORE_MOVED,
×
1823
                                                       existing_stack, new_stack->getamount(),
×
1824
                                                       new_stack ) )
1825
        {
1826
          if ( new_stack != this )
×
1827
            this->add_to_self( new_stack );
×
1828
          return new BError( "Could not add to existing stack" );
×
1829
        }
1830
      }
1831
      else
1832
        return create_new_stack();
1✔
1833

1834
      u16 amount = new_stack->getamount();
×
1835
      existing_stack->add_to_self( new_stack );
×
1836
      update_item_to_inrange( existing_stack );
×
1837

1838
      UpdateCharacterWeight( existing_stack );
×
1839

1840
      newcontainer->on_insert_increase_stack( nullptr, Core::UContainer::MT_CORE_MOVED,
×
1841
                                              existing_stack, amount );
1842

1843
      if ( amt == item_amount )
×
1844
        destroy_item( this );
×
1845
      else
1846
        update_item_to_inrange( this );
×
1847

1848
      return new Module::EItemRefObjImp( existing_stack );
×
1849
    }
1850
    return create_new_stack();
×
1851

1852
    break;
1853
  }
1854
  case MTH_HAS_EXISTING_STACK:
×
1855
  {
1856
    Item* cont = nullptr;
×
1857

1858
    if ( !ex.hasParams( 1 ) )
×
1859
      return new BError( "Not enough params" );
×
1860
    if ( !ex.getItemParam( 0, cont ) )
×
1861
      return new BError( "No container specified" );
×
1862
    if ( this->inuse() )
×
1863
      return new BError( "Item is in use" );
×
1864
    if ( !cont->isa( Core::UOBJ_CLASS::CLASS_CONTAINER ) )
×
1865
      return new BError( "Non-container selected as target" );
×
1866

1867
    Core::UContainer* stackcontainer = static_cast<Core::UContainer*>( cont );
×
1868

1869
    Item* existing_stack = stackcontainer->find_addable_stack( this );
×
1870

1871
    if ( existing_stack != nullptr )
×
1872
      return new Module::EItemRefObjImp( existing_stack );
×
1873
    return nullptr;
×
1874

1875
    break;
1876
  }
1877
  default:
32✔
1878
    return nullptr;
32✔
1879
  }
1880
}
1881

1882
BObjectImp* Item::script_method( const char* methodname, Core::UOExecutor& ex )
×
1883
{
1884
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
1885
  if ( objmethod != nullptr )
×
1886
    return this->script_method_id( objmethod->id, ex );
×
1887
  return nullptr;
×
1888
}
1889

1890
BObjectImp* Item::custom_script_method( const char* methodname, Core::UOExecutor& ex )
7✔
1891
{
1892
  const ItemDesc& id = itemdesc();
7✔
1893
  if ( id.method_script != nullptr )
7✔
1894
  {
1895
    unsigned PC;
1896
    if ( id.method_script->FindExportedFunction(
6✔
1897
             methodname, static_cast<unsigned int>( ex.numParams() + 1 ), PC ) )
6✔
1898
      return id.method_script->call( PC, make_ref(), ex.fparams );
6✔
1899
  }
1900
  return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
1✔
1901
}
1902

1903
BObject Item::call_custom_method( const char* methodname )
×
1904
{
1905
  // no systemhook needed used for openbook uo module function
1906
  BObjectImpRefVec noparams;
×
1907
  return call_custom_method( methodname, noparams );
×
1908
}
×
1909

1910
BObject Item::call_custom_method( const char* methodname, BObjectImpRefVec& pmore )
×
1911
{
1912
  // no systemhook needed used for openbook uo module function
1913
  const ItemDesc& id = itemdesc();
×
1914
  if ( id.method_script != nullptr )
×
1915
  {
1916
    unsigned PC;
1917
    if ( id.method_script->FindExportedFunction(
×
1918
             methodname, static_cast<unsigned int>( pmore.size() + 1 ), PC ) )
×
1919
      return id.method_script->call( PC, new Module::EItemRefObjImp( this ), pmore );
×
1920

1921
    std::string message;
×
1922
    message = "Method script for objtype " + id.objtype_description() +
×
1923
              " does not export function " + std::string( methodname ) + " taking " +
×
1924
              Clib::tostring( pmore.size() + 1 ) + " parameters";
×
1925
    BError* err = new BError( message );
×
1926
    return BObject( err );
×
1927
  }
×
1928
  return BObject( new BError( "No method script defined for " + id.objtype_description() ) );
×
1929
}
1930

1931
BObjectImp* Item::make_ref()
167✔
1932
{
1933
  return new Module::EItemRefObjImp( this );
167✔
1934
}
1935
}  // namespace Items
1936
namespace Mobile
1937
{
1938
using namespace Bscript;
1939

1940
class ARUpdater
1941
{
1942
public:
1943
  static void on_change( Character* chr )
×
1944
  {
1945
    chr->refresh_ar();  // FIXME inefficient
×
1946
    // if (chr->client != nullptr) // already send in refresh_ar()
1947
    //{
1948
    //  send_full_statmsg( chr->client, chr );
1949
    //}
1950
  }
×
1951
};
1952

1953
BObjectImp* Character::make_ref()
25✔
1954
{
1955
  return new Module::ECharacterRefObjImp( this );
25✔
1956
}
1957
BObjectImp* Character::make_offline_ref()
26✔
1958
{
1959
  return new Module::EOfflineCharacterRefObjImp( this );
26✔
1960
}
1961

1962
BObjectImp* Character::get_script_member_id( const int id ) const
916✔
1963
{
1964
  BObjectImp* imp = base::get_script_member_id( id );
916✔
1965
  if ( imp != nullptr )
916✔
1966
    return imp;
622✔
1967

1968

1969
  auto EnforceCaps = []( s16 baseValue, const s16 capValue ) -> s16
36✔
1970
  {
1971
    const bool ignore_caps = Core::settingsManager.ssopt.core_ignores_defence_caps;
36✔
1972

1973

1974
    if ( !ignore_caps )
36✔
1975
      baseValue = std::min( baseValue, capValue );
36✔
1976

1977
    return baseValue;
36✔
1978
  };
1979

1980
  switch ( id )
294✔
1981
  {
1982
  case MBR_WARMODE:
×
1983
    return new BLong( warmode() );
×
1984
    break;
1985
  case MBR_GENDER:
1✔
1986
    return new BLong( gender );
1✔
1987
    break;
1988
  case MBR_RACE:
1✔
1989
    return new BLong( race );
1✔
1990
    break;
1991
  case MBR_TRUEOBJTYPE:
1✔
1992
    return new BLong( trueobjtype );
1✔
1993
    break;
1994
  case MBR_TRUECOLOR:
1✔
1995
    return new BLong( truecolor );
1✔
1996
    break;
1997
  case MBR_POSITION_CHANGED_AT:
2✔
1998
    return new Double( static_cast<double>( Core::polclock_t_to_ms( position_changed_at_ ) ) );
2✔
1999
    break;
2000
  case MBR_MOVED_AT:
2✔
2001
    return new Double( static_cast<double>( Core::polclock_t_to_ms( moved_at_ ) ) );
2✔
2002
    break;
2003
  case MBR_AR_MOD:
×
2004
    return new BLong( ar_mod() );
×
2005
    break;
2006
  case MBR_DELAY_MOD:
×
2007
    return new BLong( delay_mod() );
×
2008
    break;
2009
  case MBR_HIDDEN:
1✔
2010
    return new BLong( hidden() ? 1 : 0 );
1✔
2011
    break;
2012
  case MBR_CONCEALED:
1✔
2013
    return new BLong( concealed() );
1✔
2014
    break;
2015
  case MBR_FROZEN:
1✔
2016
    return new BLong( frozen() ? 1 : 0 );
1✔
2017
    break;
2018
  case MBR_PARALYZED:
×
2019
    return new BLong( paralyzed() ? 1 : 0 );
×
2020
    break;
2021
  case MBR_POISONED:
×
2022
    return new BLong( poisoned() ? 1 : 0 );
×
2023
    break;
2024
  case MBR_STEALTHSTEPS:
×
2025
    return new BLong( stealthsteps_ );
×
2026
    break;
2027
  case MBR_MOUNTEDSTEPS:
1✔
2028
    return new BLong( mountedsteps_ );
1✔
2029
    break;
2030
  case MBR_SQUELCHED:
1✔
2031
    return new BLong( squelched() ? 1 : 0 );
1✔
2032
    break;
2033
  case MBR_DEAD:
1✔
2034
    return new BLong( dead() );
1✔
2035
    break;
2036
  case MBR_AR:
3✔
2037
    return new BLong( ar() );
3✔
2038
    break;
2039
  case MBR_BACKPACK:
30✔
2040
  {
2041
    Items::Item* bp = backpack();
30✔
2042
    if ( bp != nullptr )
30✔
2043
      return bp->make_ref();
27✔
2044
    return new BError( "That has no backpack" );
3✔
2045
    break;
2046
  }
2047
  case MBR_TRADEWINDOW:
×
2048
  {
2049
    Core::UContainer* tw = trading_cont.get();
×
2050
    if ( trading_with != nullptr )
×
2051
      return tw->make_ref();
×
2052
    return new BError( "That has no active tradewindow" );
×
2053
    break;
2054
  }
2055
  case MBR_WEAPON:
1✔
2056
    if ( weapon != nullptr )
1✔
2057
      return weapon->make_ref();
1✔
2058
    return new BLong( 0 );
×
2059
    break;
2060
  case MBR_SHIELD:
1✔
2061
    if ( shield != nullptr )
1✔
2062
      return shield->make_ref();
1✔
2063
    return new BLong( 0 );
×
2064
    break;
2065
  case MBR_ACCTNAME:
×
2066
    if ( acct != nullptr )
×
2067
      return new String( acct->name() );
×
2068
    return new BError( "Not attached to an account" );
×
2069
    break;
2070

2071
  case MBR_ACCT:
×
2072
    if ( acct != nullptr )
×
2073
      return new Accounts::AccountObjImp( Accounts::AccountPtrHolder( acct ) );
×
2074
    return new BError( "Not attached to an account" );
×
2075
    break;
2076
  case MBR_CMDLEVEL:
1✔
2077
    return new BLong( cmdlevel() );
1✔
2078
    break;
2079
  case MBR_CMDLEVELSTR:
×
2080
    return new String( Core::gamestate.cmdlevels[cmdlevel()].name );
×
2081
    break;
2082
  case MBR_CRIMINAL:
×
2083
    return new BLong( is_criminal() ? 1 : 0 );
×
2084
    break;
2085
  case MBR_TEMPORALLY_CRIMINAL:
×
2086
    return new BLong( is_temporally_criminal() ? 1 : 0 );
×
2087
    break;
2088
  case MBR_IP:
×
2089
    if ( client != nullptr )
×
2090
      return new String( client->ipaddrAsString() );
×
2091
    return new String( "" );
×
2092
    break;
2093
  case MBR_GOLD:
×
2094
    return new BLong( gold_carried() );
×
2095
    break;
2096

2097
  case MBR_TITLE_PREFIX:
1✔
2098
    return new String( title_prefix() );
1✔
2099
    break;
2100
  case MBR_TITLE_SUFFIX:
1✔
2101
    return new String( title_suffix() );
1✔
2102
    break;
2103
  case MBR_TITLE_GUILD:
1✔
2104
    return new String( title_guild() );
1✔
2105
    break;
2106
  case MBR_TITLE_RACE:
1✔
2107
    return new String( title_race() );
1✔
2108
    break;
2109
  case MBR_UCLANG:
×
2110
    return new String( uclang );
×
2111
    break;
2112
  case MBR_GUILDID:
×
2113
    return new BLong( guildid() );
×
2114
    break;
2115
  case MBR_GUILD:
×
2116
    if ( has_guild() )
×
2117
      return Module::GuildExecutorModule::CreateGuildRefObjImp( guild() );
×
2118
    return new BError( "Not a member of a guild" );
×
2119
    break;
2120

2121
  case MBR_MURDERER:
1✔
2122
    return new BLong( is_murderer() ? 1 : 0 );
1✔
2123
    break;
2124
  case MBR_ATTACHED:
×
2125
    if ( script_ex == nullptr )
×
2126
      return new BError( "No script attached." );
×
2127
    return new Core::ScriptExObjImp( script_ex );
×
2128
    break;
2129
  case MBR_CLIENTVERSION:
×
2130
    if ( client != nullptr )
×
2131
      return new String( client->getversion() );
×
2132
    return new String( "" );
×
2133
    break;
2134
  case MBR_CLIENTVERSIONDETAIL:
×
2135
    if ( client != nullptr )
×
2136
    {
2137
      std::unique_ptr<BStruct> info( new BStruct );
×
2138
      Network::VersionDetailStruct version = client->getversiondetail();
×
2139
      info->addMember( "major", new BLong( version.major ) );
×
2140
      info->addMember( "minor", new BLong( version.minor ) );
×
2141
      info->addMember( "rev", new BLong( version.rev ) );
×
2142
      info->addMember( "patch", new BLong( version.patch ) );
×
2143
      return info.release();
×
2144
    }
×
2145
    else
2146
    {
2147
      std::unique_ptr<BStruct> info( new BStruct );
×
2148
      info->addMember( "major", new BLong( 0 ) );
×
2149
      info->addMember( "minor", new BLong( 0 ) );
×
2150
      info->addMember( "rev", new BLong( 0 ) );
×
2151
      info->addMember( "patch", new BLong( 0 ) );
×
2152
      return info.release();
×
2153
    }
×
2154
    break;
2155

2156
  case MBR_CLIENTINFO:
×
2157
    if ( client != nullptr )
×
2158
      return client->getclientinfo();
×
2159
    return new BLong( 0 );
×
2160
    break;
2161

2162
  case MBR_CREATEDAT:
×
2163
    return new BLong( created_at );
×
2164
    break;
2165

2166
  case MBR_REPORTABLES:
2✔
2167
    return GetReportables();
2✔
2168
    break;
2169

2170
  case MBR_OPPONENT:
×
NEW
2171
    if ( opponent_ )
×
NEW
2172
      return opponent_.object()->make_ref();
×
UNCOV
2173
    return new BError( "Mobile does not have any opponent selected." );
×
2174
    break;
2175
  case MBR_CONNECTED:
×
2176
    return new BLong( connected() ? 1 : 0 );
×
2177
    break;
2178
  case MBR_TRADING_WITH:
×
2179
    if ( trading_with != nullptr )
×
2180
      return trading_with->make_ref();
×
2181
    return new BError( "Mobile is not currently trading with anyone." );
×
2182
    break;
2183
  case MBR_CLIENTTYPE:
×
2184
    return new BLong( client != nullptr ? client->ClientType : 0 );
×
2185
    break;
2186
  case MBR_CURSOR:
×
2187
    if ( client != nullptr )
×
2188
      return new BLong( target_cursor_busy() ? 1 : 0 );
×
2189
    return new BLong( 0 );
×
2190
    break;
2191
  case MBR_GUMP:
×
2192
    if ( client != nullptr )
×
2193
      return new BLong( has_active_gump() ? 1 : 0 );
×
2194
    return new BLong( 0 );
×
2195
    break;
2196
  case MBR_PROMPT:
×
2197
    if ( client != nullptr )
×
2198
      return new BLong( has_active_prompt() ? 1 : 0 );
×
2199
    return new BLong( 0 );
×
2200
    break;
2201
  case MBR_MOVEMODE:
1✔
2202
  {
2203
    std::string mode = "";
1✔
2204
    if ( movemode & Plib::MOVEMODE_LAND )
1✔
2205
      mode = "L";
×
2206
    if ( movemode & Plib::MOVEMODE_SEA )
1✔
2207
      mode += "S";
×
2208
    if ( movemode & Plib::MOVEMODE_AIR )
1✔
2209
      mode += "A";
1✔
2210
    if ( movemode & Plib::MOVEMODE_FLY )
1✔
2211
      mode += "F";
×
2212
    return new String( mode );
1✔
2213
    break;
2214
  }
1✔
2215
  case MBR_HITCHANCE_MOD:
×
2216
    return new BLong( hitchance_mod() );
×
2217
    break;
2218
  case MBR_EVASIONCHANCE_MOD:
×
2219
    return new BLong( evasionchance_mod() );
×
2220
    break;
2221
  case MBR_PARRYCHANCE_MOD:
×
2222
    return new BLong( parrychance_mod() );
×
2223
    break;
2224
  case MBR_CARRYINGCAPACITY_MOD:
1✔
2225
    return new BLong( carrying_capacity_mod() );
1✔
2226
    break;
2227
  case MBR_CARRYINGCAPACITY:
×
2228
    return new BLong( carrying_capacity() );
×
2229
    break;
2230
  case MBR_FIRE_RESIST:
6✔
2231
    return new BLong( EnforceCaps( fire_resist().sum(), fire_resist_cap().sum() ) );
6✔
2232
  case MBR_COLD_RESIST:
6✔
2233
    return new BLong( EnforceCaps( cold_resist().sum(), cold_resist_cap().sum() ) );
6✔
2234
  case MBR_ENERGY_RESIST:
6✔
2235
    return new BLong( EnforceCaps( energy_resist().sum(), energy_resist_cap().sum() ) );
6✔
2236
  case MBR_POISON_RESIST:
6✔
2237
    return new BLong( EnforceCaps( poison_resist().sum(), poison_resist_cap().sum() ) );
6✔
2238
  case MBR_PHYSICAL_RESIST:
6✔
2239
    return new BLong( EnforceCaps( physical_resist().sum(), physical_resist_cap().sum() ) );
6✔
2240
  case MBR_FIRE_RESIST_MOD:
×
2241
    return new BLong( fire_resist().mod );
×
2242
    break;
2243
  case MBR_COLD_RESIST_MOD:
×
2244
    return new BLong( cold_resist().mod );
×
2245
    break;
2246
  case MBR_ENERGY_RESIST_MOD:
×
2247
    return new BLong( energy_resist().mod );
×
2248
    break;
2249
  case MBR_POISON_RESIST_MOD:
×
2250
    return new BLong( poison_resist().mod );
×
2251
    break;
2252
  case MBR_PHYSICAL_RESIST_MOD:
×
2253
    return new BLong( physical_resist().mod );
×
2254
    break;
2255
  case MBR_FIRE_RESIST_CAP:
2✔
2256
    return new BLong( fire_resist_cap().sum() );
2✔
2257
    break;
2258
  case MBR_COLD_RESIST_CAP:
2✔
2259
    return new BLong( cold_resist_cap().sum() );
2✔
2260
    break;
2261
  case MBR_ENERGY_RESIST_CAP:
2✔
2262
    return new BLong( energy_resist_cap().sum() );
2✔
2263
    break;
2264
  case MBR_POISON_RESIST_CAP:
2✔
2265
    return new BLong( poison_resist_cap().sum() );
2✔
2266
    break;
2267
  case MBR_PHYSICAL_RESIST_CAP:
2✔
2268
    return new BLong( physical_resist_cap().sum() );
2✔
2269
    break;
2270
  case MBR_FIRE_RESIST_CAP_MOD:
×
2271
    return new BLong( fire_resist_cap().mod );
×
2272
    break;
2273
  case MBR_COLD_RESIST_CAP_MOD:
×
2274
    return new BLong( cold_resist_cap().mod );
×
2275
    break;
2276
  case MBR_ENERGY_RESIST_CAP_MOD:
×
2277
    return new BLong( energy_resist_cap().mod );
×
2278
    break;
2279
  case MBR_POISON_RESIST_CAP_MOD:
×
2280
    return new BLong( poison_resist_cap().mod );
×
2281
    break;
2282
  case MBR_PHYSICAL_RESIST_CAP_MOD:
×
2283
    return new BLong( physical_resist_cap().mod );
×
2284
    break;
2285
  case MBR_LOWER_REAG_COST:
6✔
2286
    return new BLong( lower_reagent_cost().sum() );
6✔
2287
    break;
2288
  case MBR_SPELL_DAMAGE_INCREASE:
6✔
2289
    return new BLong( spell_damage_increase().sum() );
6✔
2290
    break;
2291
  case MBR_FASTER_CASTING:
6✔
2292
    return new BLong( faster_casting().sum() );
6✔
2293
    break;
2294
  case MBR_FASTER_CAST_RECOVERY:
6✔
2295
    return new BLong( faster_cast_recovery().sum() );
6✔
2296
    break;
2297
  case MBR_LOWER_REAG_COST_MOD:
×
2298
    return new BLong( lower_reagent_cost().mod );
×
2299
    break;
2300
  case MBR_SPELL_DAMAGE_INCREASE_MOD:
×
2301
    return new BLong( spell_damage_increase().mod );
×
2302
    break;
2303
  case MBR_FASTER_CASTING_MOD:
×
2304
    return new BLong( faster_casting().mod );
×
2305
    break;
2306
  case MBR_FASTER_CAST_RECOVERY_MOD:
×
2307
    return new BLong( faster_cast_recovery().mod );
×
2308
    break;
2309
  case MBR_DEFENCE_CHANCE_INCREASE_MOD:
×
2310
    return new BLong( defence_increase().mod );
×
2311
    break;
2312
  case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
×
2313
    return new BLong( defence_increase_cap().mod );
×
2314
    break;
2315
  case MBR_LOWER_MANA_COST_MOD:
×
2316
    return new BLong( lower_mana_cost().mod );
×
2317
    break;
2318
  case MBR_HIT_CHANCE_MOD:
×
2319
    return new BLong( hit_chance().mod );
×
2320
    break;
2321
  case MBR_DEFENCE_CHANCE_INCREASE:
6✔
2322
    return new BLong( EnforceCaps( defence_increase().sum(), defence_increase_cap().sum() ) );
6✔
2323
    break;
2324
  case MBR_DEFENCE_CHANCE_INCREASE_CAP:
2✔
2325
    return new BLong( defence_increase_cap().sum() );
2✔
2326
    break;
2327
  case MBR_LOWER_MANA_COST:
6✔
2328
    return new BLong( lower_mana_cost().sum() );
6✔
2329
    break;
2330
  case MBR_HIT_CHANCE:
6✔
2331
    return new BLong( hit_chance().sum() );
6✔
2332
    break;
2333
  case MBR_STATCAP:
1✔
2334
    return new BLong( skillstatcap().statcap );
1✔
2335
    break;
2336
  case MBR_SKILLCAP:
1✔
2337
    return new BLong( skillstatcap().skillcap );
1✔
2338
    break;
2339
  case MBR_LUCK:
6✔
2340
    return new BLong( luck().sum() );
6✔
2341
    break;
2342
  case MBR_LUCK_MOD:
×
2343
    return new BLong( luck().mod );
×
2344
    break;
2345
  case MBR_SWING_SPEED_INCREASE:
6✔
2346
    return new BLong( swing_speed_increase().sum() );
6✔
2347
    break;
2348
  case MBR_SWING_SPEED_INCREASE_MOD:
×
2349
    return new BLong( swing_speed_increase().mod );
×
2350
    break;
2351
  case MBR_MIN_ATTACK_RANGE_INCREASE:
6✔
2352
    return new BLong( min_attack_range_increase().sum() );
6✔
2353
    break;
2354
  case MBR_MIN_ATTACK_RANGE_INCREASE_MOD:
×
2355
    return new BLong( min_attack_range_increase().mod );
×
2356
    break;
2357
  case MBR_MAX_ATTACK_RANGE_INCREASE:
6✔
2358
    return new BLong( max_attack_range_increase().sum() );
6✔
2359
    break;
2360
  case MBR_MAX_ATTACK_RANGE_INCREASE_MOD:
×
2361
    return new BLong( max_attack_range_increase().mod );
×
2362
    break;
2363
  case MBR_FOLLOWERSMAX:
1✔
2364
    return new BLong( followers().followers_max );
1✔
2365
    break;
2366
  case MBR_TITHING:
1✔
2367
    return new BLong( tithing() );
1✔
2368
    break;
2369
  case MBR_FOLLOWERS:
1✔
2370
    return new BLong( followers().followers );
1✔
2371
    break;
2372
  case MBR_FIRE_DAMAGE:
6✔
2373
    return new BLong( fire_damage().sum() );
6✔
2374
    break;
2375
  case MBR_COLD_DAMAGE:
6✔
2376
    return new BLong( cold_damage().sum() );
6✔
2377
    break;
2378
  case MBR_ENERGY_DAMAGE:
6✔
2379
    return new BLong( energy_damage().sum() );
6✔
2380
    break;
2381
  case MBR_POISON_DAMAGE:
6✔
2382
    return new BLong( poison_damage().sum() );
6✔
2383
    break;
2384
  case MBR_PHYSICAL_DAMAGE:
6✔
2385
    return new BLong( physical_damage().sum() );
6✔
2386
    break;
2387
  case MBR_FIRE_DAMAGE_MOD:
×
2388
    return new BLong( fire_damage().mod );
×
2389
    break;
2390
  case MBR_COLD_DAMAGE_MOD:
×
2391
    return new BLong( cold_damage().mod );
×
2392
    break;
2393
  case MBR_ENERGY_DAMAGE_MOD:
×
2394
    return new BLong( energy_damage().mod );
×
2395
    break;
2396
  case MBR_POISON_DAMAGE_MOD:
×
2397
    return new BLong( poison_damage().mod );
×
2398
    break;
2399
  case MBR_PHYSICAL_DAMAGE_MOD:
×
2400
    return new BLong( physical_damage().mod );
×
2401
    break;
2402
  case MBR_PARTY:
6✔
2403
    if ( has_party() )
6✔
2404
      return Module::CreatePartyRefObjImp( party() );
6✔
2405
    return new BError( "Not a member of a party" );
×
2406
    break;
2407
  case MBR_PARTYLOOT:
×
2408
    return new BLong( party_can_loot() );
×
2409
  case MBR_CANDIDATE_OF_PARTY:
×
2410
    if ( has_candidate_of() )
×
2411
      return Module::CreatePartyRefObjImp( candidate_of() );
×
2412
    return new BError( "Not a candidate of a party" );
×
2413
    break;
2414
  case MBR_MOVECOST_WALK:
1✔
2415
    return new Double( movement_cost().walk );
1✔
2416
    break;
2417
  case MBR_MOVECOST_RUN:
1✔
2418
    return new Double( movement_cost().run );
1✔
2419
    break;
2420
  case MBR_MOVECOST_WALK_MOUNTED:
1✔
2421
    return new Double( movement_cost().walk_mounted );
1✔
2422
    break;
2423
  case MBR_MOVECOST_RUN_MOUNTED:
1✔
2424
    return new Double( movement_cost().run_mounted );
1✔
2425
    break;
2426

2427
  case MBR_AGGRESSORTO:
×
2428
    return GetAggressorTo();
×
2429
    break;
2430
  case MBR_LAWFULLYDAMAGED:
×
2431
    return GetLawFullyDamaged();
×
2432
    break;
2433

2434
  case MBR_UO_EXPANSION_CLIENT:
×
2435
    return new BLong( client != nullptr ? client->UOExpansionFlagClient : 0 );
×
2436
    break;
2437

2438
  case MBR_DEAFENED:
1✔
2439
    return new BLong( deafened() ? 1 : 0 );
1✔
2440
    break;
2441

2442
  case MBR_CLIENT:
12✔
2443
    if ( ( client != nullptr ) && ( client->isConnected() ) )
12✔
2444
      return client->make_ref();
11✔
2445
    return new BError( "No client attached." );
1✔
2446
    break;
2447
  case MBR_EDITING:
×
2448
    return new BLong( is_house_editing() ? 1 : 0 );
×
2449
    break;
2450
  case MBR_LASTCOORD:
×
2451
    if ( client != nullptr )
×
2452
    {
2453
      std::unique_ptr<BStruct> lastcoord( new BStruct );
×
2454
      lastcoord->addMember( "lastx", new BLong( lastpos.x() ) );
×
2455
      lastcoord->addMember( "lasty", new BLong( lastpos.y() ) );
×
2456
      lastcoord->addMember( "lastz", new BLong( lastpos.z() ) );
×
2457
      return lastcoord.release();
×
2458
    }
×
2459
    return new BError( "No client attached." );
×
2460
  case MBR_ACTIVE_SKILL:
×
2461
    return new BLong( skill_ex_active() );
×
2462
  case MBR_CASTING_SPELL:
×
2463
    return new BLong( casting_spell() );
×
2464
  case MBR_LAST_TEXTCOLOR:
×
2465
    return new BLong( last_textcolor() );
×
2466
  case MBR_BUFFS:
3✔
2467
  {
2468
    auto buffs = std::make_unique<BDictionary>();
3✔
2469
    for ( const auto& [icon, buf] : buffs_ )
5✔
2470
    {
2471
      auto info = std::make_unique<BStruct>();
2✔
2472
      info->addMember( "name_cliloc", new BLong( buf.cl_name ) );
2✔
2473
      info->addMember( "desc_cliloc", new BLong( buf.cl_descr ) );
2✔
2474
      info->addMember( "end_time", new BLong( buf.end ) );
2✔
2475
      info->addMember( "name_args", new String( buf.name_arguments ) );
2✔
2476
      info->addMember( "desc_args", new String( buf.desc_arguments ) );
2✔
2477
      buffs->addMember( new BLong( icon ), info.release() );
2✔
2478
    }
2✔
2479
    return buffs.release();
3✔
2480
  }
3✔
2481
  case MBR_LOGGED_IN:
6✔
2482
    return new BLong( logged_in() ? 1 : 0 );
6✔
2483
    break;
2484
  }
2485
  // if all else fails, returns nullptr
2486
  return nullptr;
60✔
2487
}
2488

2489
BObjectImp* Character::get_script_member( const char* membername ) const
108✔
2490
{
2491
  ObjMember* objmember = getKnownObjMember( membername );
108✔
2492
  if ( objmember != nullptr )
108✔
2493
    return this->get_script_member_id( objmember->id );
108✔
2494
  return nullptr;
×
2495
}
2496

2497
BObjectImp* Character::set_script_member_id( const int id, const std::string& value )
17✔
2498
{
2499
  BObjectImp* imp = base::set_script_member_id( id, value );
17✔
2500
  if ( imp != nullptr )
17✔
2501
    return imp;
×
2502

2503
  String* ret;
2504
  switch ( id )
17✔
2505
  {
2506
  case MBR_TITLE_PREFIX:
4✔
2507
    title_prefix( value );
4✔
2508
    ret = new String( value );
4✔
2509
    break;
4✔
2510
  case MBR_TITLE_SUFFIX:
4✔
2511
    title_suffix( value );
4✔
2512
    ret = new String( value );
4✔
2513
    break;
4✔
2514
  case MBR_TITLE_GUILD:
5✔
2515
    title_guild( value );
5✔
2516
    ret = new String( value );
5✔
2517
    break;
5✔
2518
  case MBR_TITLE_RACE:
4✔
2519
    title_race( value );
4✔
2520
    ret = new String( value );
4✔
2521
    break;
4✔
2522
  default:
×
2523
    return nullptr;
×
2524
  }
2525
  set_dirty();
17✔
2526
  increv();
17✔
2527
  if ( this->has_active_client() )
17✔
2528
    send_object_cache_to_inrange( this );
13✔
2529
  return ret;
17✔
2530
}
2531

2532
BObjectImp* Character::set_script_member( const char* membername, const std::string& value )
4✔
2533
{
2534
  ObjMember* objmember = getKnownObjMember( membername );
4✔
2535
  if ( objmember != nullptr )
4✔
2536
    return this->set_script_member_id( objmember->id, value );
4✔
2537
  return nullptr;
×
2538
}
2539

2540
BObjectImp* Character::set_script_member_id( const int id, int value )
99✔
2541
{
2542
  BObjectImp* imp = base::set_script_member_id( id, value );
99✔
2543
  if ( imp != nullptr )
99✔
2544
    return imp;
×
2545

2546
  switch ( id )
99✔
2547
  {
2548
  case MBR_GENDER:
1✔
2549
    if ( value )
1✔
2550
      gender = Plib::GENDER_FEMALE;
1✔
2551
    else
2552
      gender = Plib::GENDER_MALE;
×
2553
    return new BLong( gender );
1✔
2554
  case MBR_RACE:
1✔
2555
    if ( value == Plib::RACE_HUMAN )
1✔
2556
      race = Plib::RACE_HUMAN;
×
2557
    else if ( value == Plib::RACE_ELF )
1✔
2558
      race = Plib::RACE_ELF;
×
2559
    else if ( value == Plib::RACE_GARGOYLE )
1✔
2560
      race = Plib::RACE_GARGOYLE;
1✔
2561
    if ( ( race != Plib::RACE_GARGOYLE ) &&
1✔
2562
         ( movemode & Plib::MOVEMODE_FLY ) )                         // FIXME graphic based maybe?
×
2563
      movemode = (Plib::MOVEMODE)( movemode ^ Plib::MOVEMODE_FLY );  // remove flying
×
2564
    return new BLong( race );
1✔
2565
  case MBR_TRUEOBJTYPE:
1✔
2566
    return new BLong( trueobjtype = Clib::clamp_convert<u32>( value ) );
1✔
2567
  case MBR_TRUECOLOR:
1✔
2568
    return new BLong( truecolor = Clib::clamp_convert<u16>( value ) );
1✔
2569
  case MBR_AR_MOD:
1✔
2570
    ar_mod( Clib::clamp_convert<s16>( value ) );
1✔
2571
    refresh_ar();
1✔
2572
    return new BLong( ar_mod() );
1✔
2573
  case MBR_DELAY_MOD:
×
2574
    delay_mod( Clib::clamp_convert<s16>( value ) );
×
2575
    return new BLong( delay_mod() );
×
2576
  case MBR_HIDDEN:
12✔
2577
  {
2578
    // FIXME: don't call on_change unless the value actually changed?
2579
    hidden( value ? true : false );
12✔
2580
    return new BLong( hidden() );
12✔
2581
  }
2582
  case MBR_CONCEALED:
1✔
2583
    concealed( Clib::clamp_convert<u8>( value ) );
1✔
2584
    return new BLong( concealed() );
1✔
2585
  case MBR_FROZEN:
1✔
2586
    mob_flags_.change( MOB_FLAGS::FROZEN, value ? true : false );
1✔
2587
    return new BLong( frozen() );
1✔
2588
  case MBR_PARALYZED:
×
2589
    mob_flags_.change( MOB_FLAGS::PARALYZED, value ? true : false );
×
2590
    return new BLong( paralyzed() );
×
2591
  case MBR_POISONED:
×
2592
    poisoned( value ? true : false );
×
2593
    return new BLong( poisoned() );
×
2594
  case MBR_STEALTHSTEPS:
×
2595
    return new BLong( stealthsteps_ = Clib::clamp_convert<u16>( value ) );
×
2596
  case MBR_MOUNTEDSTEPS:
1✔
2597
    return new BLong( mountedsteps_ = Clib::clamp_convert<u32>( value ) );
1✔
2598
  case MBR_CMDLEVEL:
1✔
2599
    if ( value >= static_cast<int>( Core::gamestate.cmdlevels.size() ) )
1✔
2600
      cmdlevel( static_cast<unsigned char>( Core::gamestate.cmdlevels.size() ) - 1, true );
×
2601
    else
2602
      cmdlevel( static_cast<unsigned char>( value ), true );
1✔
2603
    return new BLong( cmdlevel() );
1✔
2604
  case MBR_MURDERER:
1✔
2605
    // make_murderer handles the updating
2606
    make_murderer( value ? true : false );
1✔
2607
    return new BLong( is_murderer() );
1✔
2608
  case MBR_HITCHANCE_MOD:
2✔
2609
    hitchance_mod( Clib::clamp_convert<s16>( value ) );
2✔
2610
    return new BLong( hitchance_mod() );
2✔
2611
  case MBR_EVASIONCHANCE_MOD:
×
2612
    evasionchance_mod( Clib::clamp_convert<s16>( value ) );
×
2613
    return new BLong( evasionchance_mod() );
×
2614
  case MBR_PARRYCHANCE_MOD:
×
2615
    parrychance_mod( Clib::clamp_convert<s16>( value ) );
×
2616
    return new BLong( parrychance_mod() );
×
2617
  case MBR_CARRYINGCAPACITY_MOD:
1✔
2618
    carrying_capacity_mod( Clib::clamp_convert<s16>( value ) );
1✔
2619
    if ( client != nullptr )
1✔
2620
    {  // CHECKME consider sending less frequently
2621
      send_full_statmsg( client, this );
×
2622
    }
2623
    return new BLong( carrying_capacity_mod() );
1✔
2624
  case MBR_FACING:
5✔
2625
    if ( !face( static_cast<Core::UFACING>( value & PKTIN_02_FACING_MASK ), 0 ) )
5✔
2626
      return new BLong( 0 );
×
2627
    on_facing_changed();
5✔
2628
    return new BLong( 1 );
5✔
2629
  case MBR_FIRE_RESIST_MOD:
2✔
2630
    fire_resist( fire_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2631
    refresh_ar();
2✔
2632
    return new BLong( fire_resist().mod );
2✔
2633
    break;
2634
  case MBR_COLD_RESIST_MOD:
2✔
2635
    cold_resist( cold_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2636
    refresh_ar();
2✔
2637
    return new BLong( cold_resist().mod );
2✔
2638
    break;
2639
  case MBR_ENERGY_RESIST_MOD:
2✔
2640
    energy_resist( energy_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2641
    refresh_ar();
2✔
2642
    return new BLong( energy_resist().mod );
2✔
2643
    break;
2644
  case MBR_POISON_RESIST_MOD:
2✔
2645
    poison_resist( poison_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2646
    refresh_ar();
2✔
2647
    return new BLong( poison_resist().mod );
2✔
2648
    break;
2649
  case MBR_PHYSICAL_RESIST_MOD:
2✔
2650
    physical_resist( physical_resist().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2651
    refresh_ar();
2✔
2652
    return new BLong( physical_resist().mod );
2✔
2653
    break;
2654
  case MBR_LOWER_REAG_COST_MOD:
2✔
2655
    lower_reagent_cost( lower_reagent_cost().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2656
    refresh_ar();
2✔
2657
    return new BLong( lower_reagent_cost().mod );
2✔
2658
    break;
2659
  case MBR_SPELL_DAMAGE_INCREASE_MOD:
2✔
2660
    spell_damage_increase( spell_damage_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2661
    refresh_ar();
2✔
2662
    return new BLong( spell_damage_increase().mod );
2✔
2663
    break;
2664
  case MBR_FASTER_CASTING_MOD:
2✔
2665
    faster_casting( faster_casting().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2666
    refresh_ar();
2✔
2667
    return new BLong( faster_casting().mod );
2✔
2668
    break;
2669
  case MBR_FASTER_CAST_RECOVERY_MOD:
2✔
2670
    faster_cast_recovery( faster_cast_recovery().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2671
    refresh_ar();
2✔
2672
    return new BLong( faster_cast_recovery().mod );
2✔
2673
    break;
2674
  case MBR_DEFENCE_CHANCE_INCREASE_MOD:
2✔
2675
    defence_increase( defence_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2676
    refresh_ar();
2✔
2677
    return new BLong( defence_increase().mod );
2✔
2678
    break;
2679
  case MBR_DEFENCE_CHANCE_INCREASE_CAP_MOD:
1✔
2680
    defence_increase_cap( defence_increase_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
1✔
2681
    refresh_ar();
1✔
2682
    return new BLong( defence_increase_cap().mod );
1✔
2683
    break;
2684
  case MBR_LOWER_MANA_COST_MOD:
2✔
2685
    lower_mana_cost( lower_mana_cost().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2686
    refresh_ar();
2✔
2687
    return new BLong( lower_mana_cost().mod );
2✔
2688
    break;
2689
  case MBR_HIT_CHANCE_MOD:
2✔
2690
    hit_chance( hit_chance().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2691
    refresh_ar();
2✔
2692
    return new BLong( hit_chance().mod );
2✔
2693
    break;
2694
  case MBR_FIRE_RESIST_CAP_MOD:
1✔
2695
    fire_resist_cap( fire_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
1✔
2696
    refresh_ar();
1✔
2697
    return new BLong( fire_resist_cap().mod );
1✔
2698
    break;
2699
  case MBR_COLD_RESIST_CAP_MOD:
1✔
2700
    cold_resist_cap( cold_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
1✔
2701
    refresh_ar();
1✔
2702
    return new BLong( cold_resist_cap().mod );
1✔
2703
    break;
2704
  case MBR_ENERGY_RESIST_CAP_MOD:
1✔
2705
    energy_resist_cap( energy_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
1✔
2706
    refresh_ar();
1✔
2707
    return new BLong( energy_resist_cap().mod );
1✔
2708
    break;
2709
  case MBR_PHYSICAL_RESIST_CAP_MOD:
1✔
2710
    physical_resist_cap( physical_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
1✔
2711
    refresh_ar();
1✔
2712
    return new BLong( physical_resist_cap().mod );
1✔
2713
    break;
2714
  case MBR_POISON_RESIST_CAP_MOD:
1✔
2715
    poison_resist_cap( poison_resist_cap().setAsMod( Clib::clamp_convert<s16>( value ) ) );
1✔
2716
    refresh_ar();
1✔
2717
    return new BLong( poison_resist_cap().mod );
1✔
2718
    break;
2719
  case MBR_LUCK_MOD:
2✔
2720
    luck( luck().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2721
    refresh_ar();
2✔
2722
    return new BLong( luck().mod );
2✔
2723
    break;
2724
  case MBR_SWING_SPEED_INCREASE_MOD:
10✔
2725
    swing_speed_increase( swing_speed_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
10✔
2726
    refresh_ar();
10✔
2727
    return new BLong( swing_speed_increase().mod );
10✔
2728
    break;
2729
  case MBR_MIN_ATTACK_RANGE_INCREASE_MOD:
2✔
2730
    min_attack_range_increase(
4✔
2731
        min_attack_range_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2732
    refresh_ar();
2✔
2733
    return new BLong( min_attack_range_increase().mod );
2✔
2734
    break;
2735
  case MBR_MAX_ATTACK_RANGE_INCREASE_MOD:
3✔
2736
    max_attack_range_increase(
6✔
2737
        max_attack_range_increase().setAsMod( Clib::clamp_convert<s16>( value ) ) );
3✔
2738
    refresh_ar();
3✔
2739
    return new BLong( max_attack_range_increase().mod );
3✔
2740
    break;
2741
  case MBR_STATCAP:
1✔
2742
  {
2743
    auto val = skillstatcap();
1✔
2744
    val.statcap = Clib::clamp_convert<s16>( value );
1✔
2745
    skillstatcap( val );
1✔
2746
    if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
1✔
2747
      on_aos_ext_stat_changed();
1✔
2748
    return new BLong( skillstatcap().statcap );
1✔
2749
  }
2750
  case MBR_SKILLCAP:
1✔
2751
  {
2752
    auto val = skillstatcap();
1✔
2753
    val.skillcap = Clib::clamp_convert<u16>( value );
1✔
2754
    skillstatcap( val );
1✔
2755
    return new BLong( skillstatcap().skillcap );
1✔
2756
  }
2757
  case MBR_FOLLOWERSMAX:
1✔
2758
  {
2759
    auto val = followers();
1✔
2760
    val.followers_max = Clib::clamp_convert<u8>( value );
1✔
2761
    followers( val );
1✔
2762
    if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
1✔
2763
      on_aos_ext_stat_changed();
1✔
2764
    return new BLong( followers().followers_max );
1✔
2765
  }
2766
  case MBR_TITHING:
1✔
2767
    tithing( value );
1✔
2768
    if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
1✔
2769
      on_aos_ext_stat_changed();
1✔
2770
    return new BLong( tithing() );
1✔
2771
    break;
2772
  case MBR_FOLLOWERS:
1✔
2773
  {
2774
    auto val = followers();
1✔
2775
    val.followers = Clib::clamp_convert<u8>( value );
1✔
2776
    followers( val );
1✔
2777
    if ( !this->isa( Core::UOBJ_CLASS::CLASS_NPC ) )
1✔
2778
      on_aos_ext_stat_changed();
1✔
2779
    return new BLong( followers().followers );
1✔
2780
  }
2781
  case MBR_FIRE_DAMAGE_MOD:
2✔
2782
    fire_damage( fire_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2783
    refresh_ar();
2✔
2784
    return new BLong( fire_damage().mod );
2✔
2785
    break;
2786
  case MBR_COLD_DAMAGE_MOD:
2✔
2787
    cold_damage( cold_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2788
    refresh_ar();
2✔
2789
    return new BLong( cold_damage().mod );
2✔
2790
    break;
2791
  case MBR_ENERGY_DAMAGE_MOD:
2✔
2792
    energy_damage( energy_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2793
    refresh_ar();
2✔
2794
    return new BLong( energy_damage().mod );
2✔
2795
    break;
2796
  case MBR_POISON_DAMAGE_MOD:
2✔
2797
    poison_damage( poison_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2798
    refresh_ar();
2✔
2799
    return new BLong( poison_damage().mod );
2✔
2800
    break;
2801
  case MBR_PHYSICAL_DAMAGE_MOD:
2✔
2802
    physical_damage( physical_damage().setAsMod( Clib::clamp_convert<s16>( value ) ) );
2✔
2803
    refresh_ar();
2✔
2804
    return new BLong( physical_damage().mod );
2✔
2805
    break;
2806
  case MBR_MOVECOST_WALK:
×
2807
  {
2808
    auto val = movement_cost();
×
2809
    val.walk = static_cast<double>( value );
×
2810
    movement_cost( val );
×
2811
    return new Double( movement_cost().walk );
×
2812
  }
2813
  case MBR_MOVECOST_RUN:
×
2814
  {
2815
    auto val = movement_cost();
×
2816
    val.run = static_cast<double>( value );
×
2817
    movement_cost( val );
×
2818
    return new Double( movement_cost().run );
×
2819
  }
2820
  case MBR_MOVECOST_WALK_MOUNTED:
×
2821
  {
2822
    auto val = movement_cost();
×
2823
    val.walk_mounted = static_cast<double>( value );
×
2824
    movement_cost( val );
×
2825
    return new Double( movement_cost().walk_mounted );
×
2826
  }
2827
  case MBR_MOVECOST_RUN_MOUNTED:
×
2828
  {
2829
    auto val = movement_cost();
×
2830
    val.run_mounted = static_cast<double>( value );
×
2831
    movement_cost( val );
×
2832
    return new Double( movement_cost().run_mounted );
×
2833
  }
2834
  default:
7✔
2835
    return nullptr;
7✔
2836
  }
2837
}
2838

2839
BObjectImp* Character::set_script_member_id_double( const int id, double value )
4✔
2840
{
2841
  switch ( id )
4✔
2842
  {
2843
  case MBR_MOVECOST_WALK:
1✔
2844
  {
2845
    auto val = movement_cost();
1✔
2846
    val.walk = value;
1✔
2847
    movement_cost( val );
1✔
2848
    return new Double( movement_cost().walk );
1✔
2849
  }
2850
  case MBR_MOVECOST_RUN:
1✔
2851
  {
2852
    auto val = movement_cost();
1✔
2853
    val.run = value;
1✔
2854
    movement_cost( val );
1✔
2855
    return new Double( movement_cost().run );
1✔
2856
  }
2857
  case MBR_MOVECOST_WALK_MOUNTED:
1✔
2858
  {
2859
    auto val = movement_cost();
1✔
2860
    val.walk_mounted = value;
1✔
2861
    movement_cost( val );
1✔
2862
    return new Double( movement_cost().walk_mounted );
1✔
2863
  }
2864
  case MBR_MOVECOST_RUN_MOUNTED:
1✔
2865
  {
2866
    auto val = movement_cost();
1✔
2867
    val.run_mounted = value;
1✔
2868
    movement_cost( val );
1✔
2869
    return new Double( movement_cost().run_mounted );
1✔
2870
  }
2871
  default:
×
2872
    return nullptr;
×
2873
  }
2874
}
2875

2876
BObjectImp* Character::set_script_member( const char* membername, int value )
64✔
2877
{
2878
  ObjMember* objmember = getKnownObjMember( membername );
64✔
2879
  if ( objmember != nullptr )
64✔
2880
    return this->set_script_member_id( objmember->id, value );
64✔
2881
  return nullptr;
×
2882
}
2883

2884
BObjectImp* Character::script_method_id( const int id, Core::UOExecutor& ex )
392✔
2885
{
2886
  BObjectImp* imp = base::script_method_id( id, ex );
392✔
2887
  if ( imp != nullptr )
392✔
2888
    return imp;
283✔
2889

2890
  switch ( id )
109✔
2891
  {
2892
  /*
2893
  mobile.SetPoisoned( ispoisoned := 1 )
2894
  If the poisoned flag was changed, and the script has a controller
2895
  If poisoned was SET,
2896
  apply RepSystem rules (Mobile damages Mobile)
2897
  else poisoned was CLEARED, so
2898
  apply RepSystem rules (Mobile helps Mobile)
2899
  */
2900
  case MTH_SETPOISONED:
×
2901
  {
2902
    bool newval = true;
×
2903
    if ( ex.hasParams( 1 ) )
×
2904
    {
2905
      int lval;
2906
      if ( !ex.getParam( 0, lval ) )
×
2907
        return new BError( "Invalid parameter type" );
×
2908
      if ( !lval )
×
2909
        newval = false;
×
2910
    }
2911

2912
    if ( newval != poisoned() )
×
2913
    {
2914
      set_dirty();
×
2915
      poisoned( newval );
×
2916
      check_undamaged();
×
2917
      Module::UOExecutorModule* uoexec =
2918
          static_cast<Module::UOExecutorModule*>( ex.findModule( "UO" ) );
×
2919
      if ( uoexec != nullptr && uoexec->controller_.get() )
×
2920
      {
2921
        Character* attacker = uoexec->controller_.get();
×
2922
        if ( !attacker->orphan() )
×
2923
        {
2924
          if ( poisoned() )
×
2925
            attacker->repsys_on_damage( this );
×
2926
          else
2927
            attacker->repsys_on_help( this );
×
2928
        }
2929
      }
2930
    }
2931
    return new BLong( 1 );
×
2932
  }
2933

2934
  /*
2935
   mobile.SetParalyzed( isparalyzed := 1 )
2936
   If the paralyzed flag was changed, and the script has a controller
2937
   if paralyzed was SET,
2938
   apply RepSystem rules (Mobile damages Mobile)
2939
   else paralyzed was CLEARED, so
2940
   apply RepSystem rules (Mobile heals Mobile)
2941
   */
2942
  case MTH_SETPARALYZED:
×
2943
  {
2944
    bool newval = true;
×
2945
    if ( ex.hasParams( 1 ) )
×
2946
    {
2947
      int lval;
2948
      if ( !ex.getParam( 0, lval ) )
×
2949
        return new BError( "Invalid parameter type" );
×
2950
      if ( !lval )
×
2951
        newval = false;
×
2952
    }
2953

2954
    if ( newval != paralyzed() )
×
2955
    {
2956
      set_dirty();
×
2957
      mob_flags_.change( MOB_FLAGS::PARALYZED, newval );
×
2958
      check_undamaged();
×
2959
      Module::UOExecutorModule* uoexec =
2960
          static_cast<Module::UOExecutorModule*>( ex.findModule( "UO" ) );
×
2961
      if ( uoexec != nullptr && uoexec->controller_.get() )
×
2962
      {
2963
        Character* attacker = uoexec->controller_.get();
×
2964
        if ( !attacker->orphan() )
×
2965
        {
2966
          if ( paralyzed() )
×
2967
            attacker->repsys_on_damage( this );
×
2968
          else
2969
            attacker->repsys_on_help( this );
×
2970
        }
2971
      }
2972
    }
2973
    return new BLong( 1 );
×
2974
  }
2975

2976
  /*
2977
   mobile.SetCriminal( level := 1 )
2978
   if level is 0, clears the CriminalTimer
2979
   */
2980
  case MTH_SETCRIMINAL:
×
2981
  {
2982
    int level = 1;
×
2983
    if ( ex.hasParams( 1 ) )
×
2984
    {
2985
      if ( !ex.getParam( 0, level ) )
×
2986
        return new BError( "Invalid parameter type" );
×
2987
      if ( level < 0 )
×
2988
        return new BError( "Level must be >= 0" );
×
2989
    }
2990
    set_dirty();
×
2991
    // make_criminal handles the updating
2992
    make_criminal( level );
×
2993
    return new BLong( 1 );
×
2994
  }
2995

2996
  case MTH_SETLIGHTLEVEL:
×
2997
  {
2998
    int level, duration;
2999
    if ( !ex.hasParams( 2 ) )
×
3000
      return new BError( "Not enough parameters" );
×
3001
    if ( ex.getParam( 0, level ) && ex.getParam( 1, duration ) )
×
3002
    {
3003
      lightoverride( level );
×
3004

3005
      if ( duration == -1 )
×
3006
        lightoverride_until( ~0u );
×
3007
      else if ( duration == 0 )
×
3008
        lightoverride_until( 0 );
×
3009
      else
3010
        lightoverride_until( Core::read_gameclock() + duration );
×
3011

3012
      check_region_changes();
×
3013
      if ( duration == -1 )
×
3014
        return new BLong( duration );
×
3015
      return new BLong( lightoverride_until() );
×
3016
    }
3017
    break;
×
3018
  }
3019

3020
  case MTH_SETSEASON:
×
3021
  {
3022
    int season_id, playsound;
3023

3024
    if ( !ex.hasParams( 2 ) )
×
3025
      return new BError( "Not enough parameters" );
×
3026
    if ( ex.getParam( 0, season_id ) && ex.getParam( 1, playsound ) )
×
3027
    {
3028
      if ( season_id < 0 || season_id > 4 )
×
3029
        return new BError( "Invalid season id" );
×
3030

3031
      if ( client && client->getversiondetail().major >= 1 )
×
3032
      {
3033
        Network::PktHelper::PacketOut<Network::PktOut_BC> msg;
×
3034
        msg->Write<u8>( Clib::clamp_convert<u8>( season_id ) );
×
3035
        msg->Write<u8>( Clib::clamp_convert<u8>( playsound ) );
×
3036
        msg.Send( client );
×
3037
        return new BLong( 1 );
×
3038
      }
×
3039
    }
3040
    break;
×
3041
  }
3042
  case MTH_SQUELCH:
1✔
3043
  {
3044
    int duration;
3045
    if ( !ex.hasParams( 1 ) )
1✔
3046
      return new BError( "Not enough parameters" );
1✔
3047
    if ( ex.getParam( 0, duration ) )
1✔
3048
    {
3049
      set_dirty();
1✔
3050
      if ( duration == -1 )
1✔
3051
      {
3052
        squelched_until( ~0u );
×
3053
        return new BLong( -1 );
×
3054
      }
3055
      if ( duration == 0 )
1✔
3056
        squelched_until( 0 );
×
3057
      else
3058
        squelched_until( Core::read_gameclock() + duration );
1✔
3059
      return new BLong( squelched_until() );
1✔
3060
    }
3061
    break;
×
3062
  }
3063
  case MTH_ENABLE:
3✔
3064
  {
3065
    if ( !ex.hasParams( 1 ) )
3✔
3066
      return new BError( "Not enough parameters" );
3✔
3067
    const String* pstr;
3068
    if ( ex.getStringParam( 0, pstr ) )
3✔
3069
    {
3070
      if ( has_privilege( pstr->data() ) )
3✔
3071
      {
3072
        set_dirty();
3✔
3073
        set_setting( pstr->data(), true );
3✔
3074
        return new BLong( 1 );
3✔
3075
      }
3076
      return new BError( "Mobile doesn't have that privilege" );
×
3077
    }
3078
    break;
×
3079
  }
3080

3081
  case MTH_DISABLE:
2✔
3082
  {
3083
    if ( !ex.hasParams( 1 ) )
2✔
3084
      return new BError( "Not enough parameters" );
2✔
3085
    const String* pstr;
3086
    if ( ex.getStringParam( 0, pstr ) )
2✔
3087
    {
3088
      set_dirty();
2✔
3089
      set_setting( pstr->data(), false );
2✔
3090
      return new BLong( 1 );
2✔
3091
    }
3092
    break;
×
3093
  }
3094

3095
  case MTH_ENABLED:
2✔
3096
  {
3097
    if ( !ex.hasParams( 1 ) )
2✔
3098
      return new BError( "Not enough parameters" );
2✔
3099
    const String* pstr;
3100
    if ( ex.getStringParam( 0, pstr ) )
2✔
3101
      return new BLong( setting_enabled( pstr->data() ) ? 1 : 0 );
2✔
3102
    break;
×
3103
  }
3104

3105
  case MTH_PRIVILEGES:
1✔
3106
  {
3107
    std::unique_ptr<BDictionary> dict( new BDictionary );
1✔
3108
    ISTRINGSTREAM istrm( all_privs() );
1✔
3109
    std::string tmp;
1✔
3110
    while ( istrm >> tmp )
3✔
3111
    {
3112
      dict->addMember( new String( tmp ), new BLong( setting_enabled( tmp.c_str() ) ) );
2✔
3113
    }
3114
    return dict.release();
1✔
3115
    break;
3116
  }
1✔
3117

3118
  case MTH_SETCMDLEVEL:
×
3119
  {
3120
    if ( !ex.hasParams( 1 ) )
×
3121
      return new BError( "Not enough parameters" );
×
3122
    const String* pstr;
3123
    if ( ex.getStringParam( 0, pstr ) )
×
3124
    {
3125
      Core::CmdLevel* pcmdlevel = Core::find_cmdlevel( pstr->data() );
×
3126
      if ( pcmdlevel )
×
3127
      {
3128
        set_dirty();
×
3129
        cmdlevel( pcmdlevel->cmdlevel, true );
×
3130
        return new BLong( 1 );
×
3131
      }
3132
      return new BError( "No such command level" );
×
3133
    }
3134
    break;
×
3135
  }
3136
  case MTH_SPENDGOLD:
×
3137
  {
3138
    u32 amt;
3139
    if ( ex.numParams() != 1 || !ex.getParam( 0, amt ) )
×
3140
      return new BError( "Invalid parameter type" );
×
3141

3142
    if ( gold_carried() < amt )
×
3143
      return new BError( "Insufficient funds" );
×
3144

3145
    spend_gold( amt );
×
3146
    return new BLong( 1 );
×
3147
  }
3148

3149
  case MTH_SETMURDERER:
×
3150
  {
3151
    int lnewval = 1;
×
3152
    if ( ex.hasParams( 1 ) )
×
3153
    {
3154
      if ( !ex.getParam( 0, lnewval ) )
×
3155
        return new BError( "Invalid parameter type" );
×
3156
    }
3157
    set_dirty();
×
3158
    // make_murderer handles the updating
3159
    make_murderer( lnewval ? true : false );
×
3160
    return new BLong( 1 );
×
3161
  }
3162
  case MTH_REMOVEREPORTABLE:
×
3163
  {
3164
    if ( !ex.hasParams( 2 ) )
×
3165
      return new BError( "Not enough parameters" );
×
3166
    int repserial, gameclock;
3167
    if ( ex.getParam( 0, repserial ) && ex.getParam( 1, gameclock ) )
×
3168
    {
3169
      set_dirty();
×
3170
      clear_reportable( repserial, gameclock );
×
3171
      return new BLong( 1 );
×
3172
    }
3173
    break;
×
3174
  }
3175
  case MTH_GETGOTTENITEM:
3✔
3176
    if ( has_gotten_item() )
3✔
3177
      return new Module::EItemRefObjImp( gotten_item().item() );
3✔
3178
    return new BError( "Gotten Item nullptr" );
×
3179
    break;
3180
  case MTH_CLEARGOTTENITEM:
×
3181
    if ( has_gotten_item() )
×
3182
    {
3183
      clear_gotten_item();
×
3184
      return new BLong( 1 );
×
3185
    }
3186
    return new BError( "No Gotten Item" );
×
3187
    break;
3188
  case MTH_SETWARMODE:
3✔
3189
  {
3190
    int newmode;
3191
    if ( !ex.hasParams( 1 ) )
3✔
3192
      return new BError( "Not enough parameters" );
3✔
3193
    if ( ex.getParam( 0, newmode, 0, 1 ) )
3✔
3194
    {
3195
      set_warmode( ( newmode == 0 ) ? false : true );
3✔
3196
      // FIXME: Additional checks needed?
3197
      if ( client )
3✔
3198
        send_warmode();
2✔
3199
      return new BLong( warmode() );
3✔
3200
    }
3201
    break;
×
3202
  }
3203
  case MTH_GETCORPSE:
2✔
3204
  {
3205
    Core::UCorpse* corpse_obj =
3206
        static_cast<Core::UCorpse*>( Core::system_find_item( last_corpse ) );
2✔
3207
    if ( corpse_obj != nullptr && !corpse_obj->orphan() )
2✔
3208
      return new Module::EItemRefObjImp( corpse_obj );
2✔
3209
    return new BError( "No corpse was found." );
×
3210
    break;
3211
  }
3212
  case MTH_SET_SWINGTIMER:
×
3213
  {
3214
    int time;
3215
    if ( !ex.hasParams( 1 ) )
×
3216
      return new BError( "Not enough parameters" );
×
3217
    if ( ex.getParam( 0, time ) )
×
3218
    {
3219
      if ( time < 0 )
×
3220
        return new BError( "Time must be >= 0" );
×
3221
      Core::polclock_t clocks;
3222
      clocks = ( time * Core::POLCLOCKS_PER_SEC ) / 1000;
×
3223
      return new BLong( manual_set_swing_timer( clocks ) ? 1 : 0 );
×
3224
    }
3225
    break;
×
3226
  }
3227
  case MTH_ATTACK_ONCE:
×
3228
  {
NEW
3229
    if ( dead() )
×
NEW
3230
      return new BError( "Character is dead" );
×
UNCOV
3231
    if ( ex.hasParams( 1 ) )
×
3232
    {
3233
      UObject* obj;
NEW
3234
      if ( !ex.getUObjectParam( 0, obj ) )
×
UNCOV
3235
        return new BError( "Invalid parameter type" );
×
NEW
3236
      Attackable att{ obj };
×
NEW
3237
      if ( !att || !is_attackable( att ) )
×
NEW
3238
        return new BError( "Opponent is not attackable" );
×
NEW
3239
      attack( att );
×
3240
    }
3241
    else
3242
    {
NEW
3243
      auto opp = get_attackable_opponent();
×
NEW
3244
      if ( !opp )
×
UNCOV
3245
        return new BError( "No opponent" );
×
NEW
3246
      attack( opp );
×
3247
    }
3248
    return new BLong( 1 );
×
3249
    break;
3250
  }
3251
  case MTH_KILL:
74✔
3252
    if ( ex.hasParams( 1 ) )
74✔
3253
    {
3254
      Character* chr;
3255
      if ( ex.getCharacterParam( 0, chr ) )
1✔
3256
        chr->repsys_on_damage( this );
1✔
3257
    }
3258
    if ( dead() )
74✔
3259
      return new BError( "That is already dead!" );
×
3260

3261
    die();
74✔
3262
    return new BLong( 1 );
74✔
3263
    break;
3264
  case MTH_SETFACING:
×
3265
  {
3266
    int flags = 0;
×
3267
    Core::UFACING i_facing;
3268

3269
    if ( ex.hasParams( 2 ) && !ex.getParam( 1, flags, 0, 1 ) )
×
3270
      return new BError( "Invalid flags for parameter 1" );
×
3271

3272
    BObjectImp* param0 = ex.getParamImp( 0 );
×
3273
    if ( auto* s = impptrIf<String>( param0 ) )
×
3274
    {
3275
      if ( DecodeFacing( s->data(), i_facing ) == false )
×
3276
        return new BError( "Invalid string for parameter 0" );
×
3277
    }
3278
    else if ( auto* l = impptrIf<BLong>( param0 ) )
×
3279
    {
3280
      i_facing = static_cast<Core::UFACING>( l->value() & PKTIN_02_FACING_MASK );
×
3281
    }
3282
    else
3283
      return new BError( "Invalid type for parameter 0" );
×
3284

3285
    if ( !face( i_facing, flags ) )
×
3286
      return new BLong( 0 );
×
3287

3288
    on_facing_changed();
×
3289
    return new BLong( 1 );
×
3290
    break;
3291
  }
3292
  case MTH_COMPAREVERSION:
×
3293
    if ( client != nullptr )
×
3294
    {
3295
      if ( !ex.hasParams( 1 ) )
×
3296
        return new BError( "Not enough parameters" );
×
3297
      const String* pstr;
3298
      if ( ex.getStringParam( 0, pstr ) )
×
3299
        return new BLong( client->compareVersion( pstr->getStringRep() ) ? 1 : 0 );
×
3300
      return new BError( "Invalid parameter type" );
×
3301
    }
3302
    return new BError( "No client attached" );
×
3303
    break;
3304
  case MTH_SETAGGRESSORTO:
×
3305
    if ( ex.hasParams( 1 ) )
×
3306
    {
3307
      Character* chr;
3308
      if ( ex.getCharacterParam( 0, chr ) )
×
3309
      {
3310
        // make_aggressor_to handles the updating
3311
        this->make_aggressor_to( chr );
×
3312
        return new BLong( 1 );
×
3313
      }
3314
      return new BError( "Invalid parameter type" );
×
3315
    }
3316
    return new BError( "Not enough parameters" );
×
3317
    break;
3318
  case MTH_SETLAWFULLYDAMAGEDTO:
×
3319
    if ( ex.hasParams( 1 ) )
×
3320
    {
3321
      Character* chr;
3322
      if ( ex.getCharacterParam( 0, chr ) )
×
3323
      {
3324
        // make_lawfullydamaged_to handled the updating
3325
        this->make_lawfullydamaged_to( chr );
×
3326
        return new BLong( 1 );
×
3327
      }
3328
      return new BError( "Invalid parameter type" );
×
3329
    }
3330
    return new BError( "Not enough parameters" );
×
3331
    break;
3332
  case MTH_CLEARAGGRESSORTO:
×
3333
    if ( ex.hasParams( 1 ) )
×
3334
    {
3335
      Character* chr;
3336
      if ( ex.getCharacterParam( 0, chr ) )
×
3337
      {
3338
        this->remove_as_aggressor_to( chr );
×
3339
        return new BLong( 1 );
×
3340
      }
3341
      return new BError( "Invalid parameter type" );
×
3342
    }
3343
    return new BError( "Not enough parameters" );
×
3344
    break;
3345
  case MTH_CLEARLAWFULLYDAMAGEDTO:
×
3346
    if ( ex.hasParams( 1 ) )
×
3347
    {
3348
      Character* chr;
3349
      if ( ex.getCharacterParam( 0, chr ) )
×
3350
      {
3351
        this->remove_as_lawful_damager( chr );
×
3352
        return new BLong( 1 );
×
3353
      }
3354
      return new BError( "Invalid parameter type" );
×
3355
    }
3356
    return new BError( "Not enough parameters" );
×
3357
    break;
3358
  case MTH_DEAF:
1✔
3359
  {
3360
    int duration;
3361
    if ( !ex.hasParams( 1 ) )
1✔
3362
      return new BError( "Not enough parameters" );
1✔
3363
    if ( ex.getParam( 0, duration ) )
1✔
3364
    {
3365
      set_dirty();
1✔
3366
      if ( duration == -1 )
1✔
3367
      {
3368
        deafened_until( ~0u );
×
3369
        return new BLong( -1 );
×
3370
      }
3371
      if ( duration == 0 )
1✔
3372
        deafened_until( 0 );
×
3373
      else
3374
        deafened_until( Core::read_gameclock() + duration );
1✔
3375
      return new BLong( deafened_until() );
1✔
3376
    }
3377
    break;
×
3378
  }
3379
  case MTH_DISABLE_SKILLS_FOR:
×
3380
  {
3381
    int duration;
3382
    if ( !ex.hasParams( 1 ) )
×
3383
      return new BError( "Not enough parameters" );
×
3384
    if ( ex.getParam( 0, duration ) )
×
3385
    {
3386
      if ( duration < 0 )
×
3387
        return new BError( "Duration must be >= 0" );
×
3388
      disable_skills_until( Core::poltime() + duration );
×
3389
      return new BLong( static_cast<int>( disable_skills_until() ) );
×
3390
    }
3391
    break;
×
3392
  }
3393
  case MTH_ADD_BUFF:
2✔
3394
  {
3395
    u16 icon;
3396
    u16 duration;
3397
    u32 cl_name;
3398
    u32 cl_descr;
3399
    const String* desc_text;
3400
    std::string name_args;
2✔
3401

3402
    if ( !ex.hasParams( 5 ) )
2✔
3403
      return new BError( "Not enough parameters" );
×
3404
    if ( ex.getParam( 0, icon ) && ex.getParam( 1, duration ) && ex.getParam( 2, cl_name ) &&
4✔
3405
         ex.getParam( 3, cl_descr ) && ex.getUnicodeStringParam( 4, desc_text ) )
4✔
3406
    {
3407
      if ( ex.hasParams( 6 ) )
2✔
3408
      {
3409
        const String* name_text;
3410
        if ( !ex.getUnicodeStringParam( 5, name_text ) )
×
3411
          break;
×
3412
        if ( name_text->length() > SPEECH_MAX_LEN )
×
3413
          return new BError( "Title text exceeds maximum size." );
×
3414
        name_args = name_text->value();
×
3415
      }
3416

3417
      if ( !( icon && cl_name && cl_descr ) )
2✔
3418
        return new BError( "Invalid parameters" );
×
3419

3420
      if ( desc_text->length() > SPEECH_MAX_LEN )
2✔
3421
        return new BError( "Text exceeds maximum size." );
×
3422

3423
      addBuff( icon, duration, cl_name, name_args, cl_descr, desc_text->value() );
2✔
3424
      return new BLong( 1 );
2✔
3425
    }
3426
    break;
×
3427
  }
2✔
3428
  case MTH_CLEAR_BUFFS:
2✔
3429
  {
3430
    clearBuffs();
2✔
3431

3432
    return new BLong( 1 );
2✔
3433
    break;
3434
  }
3435
  case MTH_DEL_BUFF:
2✔
3436
  {
3437
    u16 icon;
3438

3439
    if ( !ex.hasParams( 1 ) )
2✔
3440
      return new BError( "Not enough parameters" );
2✔
3441
    if ( ex.getParam( 0, icon ) )
2✔
3442
    {
3443
      if ( !icon )
2✔
3444
        return new BError( "Invalid parameter" );
×
3445

3446
      if ( !delBuff( icon ) )
2✔
3447
        return new BError( "Buff not found" );
1✔
3448

3449
      return new BLong( 1 );
1✔
3450
    }
3451
    break;
×
3452
  }
3453
  default:
11✔
3454
    return nullptr;
11✔
3455
  }
3456
  return new BError( "Invalid parameter type" );
×
3457
}
3458

3459

3460
BObjectImp* Character::script_method( const char* methodname, Core::UOExecutor& ex )
×
3461
{
3462
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
3463
  if ( objmethod != nullptr )
×
3464
    return this->script_method_id( objmethod->id, ex );
×
3465
  return nullptr;
×
3466
}
3467

3468
BObjectImp* Character::custom_script_method( const char* methodname, Core::UOExecutor& ex )
×
3469
{
3470
  // TODO uoclient entry deprecated
3471
  if ( Core::networkManager.uoclient_general.method_script != nullptr )
×
3472
  {
3473
    unsigned PC;
3474
    if ( Core::networkManager.uoclient_general.method_script->FindExportedFunction(
×
3475
             methodname, static_cast<unsigned int>( ex.numParams() + 1 ), PC ) )
×
3476
      return Core::networkManager.uoclient_general.method_script->call( PC, make_ref(),
×
3477
                                                                        ex.fparams );
×
3478
  }
3479
  return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
×
3480
}
3481

3482
ObjArray* Character::GetReportables() const
2✔
3483
{
3484
  std::unique_ptr<ObjArray> arr( new ObjArray );
2✔
3485

3486
  for ( auto rt : reportable_ )
4✔
3487
  {
3488
    std::unique_ptr<BObjectImp> kmember( nullptr );
2✔
3489
    Character* killer = Core::system_find_mobile( rt.serial );
2✔
3490
    if ( killer )
2✔
3491
      kmember = std::make_unique<Module::EOfflineCharacterRefObjImp>( killer );
2✔
3492
    else
3493
      kmember = std::make_unique<BError>( "Mobile not found" );
×
3494

3495
    std::unique_ptr<BStruct> elem( new BStruct );
2✔
3496
    elem->addMember( "serial", new BLong( rt.serial ) );
2✔
3497
    elem->addMember( "killer", kmember.release() );
2✔
3498
    elem->addMember( "gameclock", new BLong( static_cast<s32>( rt.polclock ) ) );
2✔
3499

3500
    arr->addElement( elem.release() );
2✔
3501
  }
2✔
3502
  return arr.release();
4✔
3503
}
2✔
3504

3505
ObjArray* Character::GetAggressorTo() const
×
3506
{
3507
  std::unique_ptr<ObjArray> arr( new ObjArray );
×
3508

3509
  for ( const auto& itr : aggressor_to_ )
×
3510
  {
3511
    std::unique_ptr<BObjectImp> member( nullptr );
×
3512
    Character* chr = Core::system_find_mobile( itr.first->serial );
×
3513
    if ( chr )
×
3514
      member = std::make_unique<Module::EOfflineCharacterRefObjImp>( chr );
×
3515
    else
3516
      member = std::make_unique<BError>( "Mobile not found" );
×
3517

3518
    std::unique_ptr<BStruct> elem( new BStruct );
×
3519
    elem->addMember( "serial", new BLong( itr.first->serial ) );
×
3520
    elem->addMember( "ref", member.release() );
×
3521
    elem->addMember( "seconds", new BLong( static_cast<s32>( ( itr.second - Core::polclock() ) /
×
3522
                                                             Core::POLCLOCKS_PER_SEC ) ) );
×
3523

3524
    arr->addElement( elem.release() );
×
3525
  }
×
3526
  return arr.release();
×
3527
}
×
3528

3529
ObjArray* Character::GetLawFullyDamaged() const
×
3530
{
3531
  std::unique_ptr<ObjArray> arr( new ObjArray );
×
3532

3533
  for ( const auto& itr : lawfully_damaged_ )
×
3534
  {
3535
    std::unique_ptr<BObjectImp> member( nullptr );
×
3536
    Character* chr = Core::system_find_mobile( itr.first->serial );
×
3537
    if ( chr )
×
3538
      member = std::make_unique<Module::EOfflineCharacterRefObjImp>( chr );
×
3539
    else
3540
      member = std::make_unique<BError>( "Mobile not found" );
×
3541

3542
    std::unique_ptr<BStruct> elem( new BStruct );
×
3543
    elem->addMember( "serial", new BLong( itr.first->serial ) );
×
3544
    elem->addMember( "ref", member.release() );
×
3545
    elem->addMember( "seconds", new BLong( static_cast<s32>( ( itr.second - Core::polclock() ) /
×
3546
                                                             Core::POLCLOCKS_PER_SEC ) ) );
×
3547

3548
    arr->addElement( elem.release() );
×
3549
  }
×
3550
  return arr.release();
×
3551
}
×
3552

3553
BObjectImp* NPC::get_script_member_id( const int id ) const
488✔
3554
{
3555
  BObjectImp* imp = base::get_script_member_id( id );
488✔
3556
  if ( imp != nullptr )
488✔
3557
    return imp;
428✔
3558

3559
  switch ( id )
60✔
3560
  {
3561
  case MBR_SCRIPT:
1✔
3562
    return new String( script );
1✔
3563
    break;
3564
  case MBR_NPCTEMPLATE:
×
3565
    return new String( template_name );
×
3566
    break;
3567
  case MBR_MASTER:
1✔
3568
  {
3569
    Character* master = master_.get();
1✔
3570
    if ( master != nullptr && !master->orphan() )
1✔
3571
      return new Module::EOfflineCharacterRefObjImp( master );
1✔
3572
    return new BLong( 0 );
×
3573
    break;
3574
  }
3575

3576
  case MBR_PROCESS:
52✔
3577
    if ( ex )
52✔
3578
      return new Core::ScriptExObjImp( ex );
52✔
3579
    return new BError( "No script running" );
×
3580
    break;
3581

3582
  case MBR_EVENTMASK:
×
3583
    if ( ex )
×
3584
      return new BLong( ex->eventmask );
×
3585
    return new BError( "No script running" );
×
3586
    break;
3587

3588
  case MBR_SPEECH_COLOR:
1✔
3589
    return new BLong( speech_color() );
1✔
3590
    break;
3591
  case MBR_SPEECH_FONT:
1✔
3592
    return new BLong( speech_font() );
1✔
3593
    break;
3594
  case MBR_USE_ADJUSTMENTS:
1✔
3595
    return new BLong( use_adjustments() ? 1 : 0 );
1✔
3596
    break;
3597
  case MBR_RUN_SPEED:
1✔
3598
    return new BLong( run_speed );
1✔
3599
    break;
3600
  case MBR_ALIGNMENT:
×
3601
    return new BLong( template_->alignment );
×
3602
    break;
3603
  case MBR_SAVEONEXIT:
×
3604
    return new BLong( saveonexit() );
×
3605
    break;
3606
  case MBR_NO_DROP_EXCEPTION:
2✔
3607
    return new BLong( no_drop_exception() );
2✔
3608
  default:
×
3609
    return nullptr;
×
3610
  }
3611
}
3612

3613
BObjectImp* NPC::get_script_member( const char* membername ) const
62✔
3614
{
3615
  ObjMember* objmember = getKnownObjMember( membername );
62✔
3616
  if ( objmember != nullptr )
62✔
3617
    return this->get_script_member_id( objmember->id );
62✔
3618
  return nullptr;
×
3619
}
3620

3621
BObjectImp* NPC::set_script_member_id( const int id, const std::string& value )
×
3622
{
3623
  BObjectImp* imp = base::set_script_member_id( id, value );
×
3624
  if ( imp != nullptr )
×
3625
    return imp;
×
3626
  switch ( id )
×
3627
  {
3628
  case MBR_SCRIPT:
×
3629
    return new String( script = value );
×
3630
  default:
×
3631
    return nullptr;
×
3632
  }
3633
}
3634

3635
BObjectImp* NPC::set_script_member( const char* membername, const std::string& value )
×
3636
{
3637
  ObjMember* objmember = getKnownObjMember( membername );
×
3638
  if ( objmember != nullptr )
×
3639
    return this->set_script_member_id( objmember->id, value );
×
3640
  return nullptr;
×
3641
}
3642

3643
BObjectImp* NPC::set_script_member_id( const int id, int value )
30✔
3644
{
3645
  BObjectImp* imp = base::set_script_member_id( id, value );
30✔
3646
  if ( imp != nullptr )
30✔
3647
    return imp;
23✔
3648
  switch ( id )
7✔
3649
  {
3650
  case MBR_SPEECH_COLOR:
×
3651
    speech_color( Clib::clamp_convert<u16>( value ) );
×
3652
    return new BLong( speech_color() );
×
3653
  case MBR_SPEECH_FONT:
×
3654
    speech_font( Clib::clamp_convert<u16>( value ) );
×
3655
    return new BLong( speech_font() );
×
3656
  case MBR_USE_ADJUSTMENTS:
×
3657
    use_adjustments( value ? true : false );
×
3658
    return new BLong( use_adjustments() );
×
3659
  case MBR_RUN_SPEED:
×
3660
    return new BLong( run_speed = Clib::clamp_convert<u16>( value ) );
×
3661
  case MBR_SAVEONEXIT:
1✔
3662
    saveonexit( value ? true : false );
1✔
3663
    return new BLong( saveonexit() );
1✔
3664
  case MBR_NO_DROP_EXCEPTION:
×
3665
    no_drop_exception( value ? true : false );
×
3666
    return new BLong( no_drop_exception() );
×
3667
  default:
6✔
3668
    return nullptr;
6✔
3669
  }
3670
}
3671
BObjectImp* NPC::set_script_member( const char* membername, int value )
×
3672
{
3673
  ObjMember* objmember = getKnownObjMember( membername );
×
3674
  if ( objmember != nullptr )
×
3675
    return this->set_script_member_id( objmember->id, value );
×
3676
  return nullptr;
×
3677
}
3678

3679
BObjectImp* NPC::script_method_id( const int id, Core::UOExecutor& executor )
186✔
3680
{
3681
  BObjectImp* imp = base::script_method_id( id, executor );
186✔
3682
  if ( imp != nullptr )
186✔
3683
    return imp;
175✔
3684

3685
  switch ( id )
11✔
3686
  {
3687
  case MTH_SETMASTER:
11✔
3688
  {
3689
    if ( executor.numParams() != 1 )
11✔
3690
      return new BError( "Not enough parameters" );
×
3691
    Character* chr;
3692
    set_dirty();
11✔
3693
    if ( executor.getCharacterParam( 0, chr ) )
11✔
3694
    {
3695
      master_.set( chr );
11✔
3696
      return new BLong( 1 );
11✔
3697
    }
3698

3699
    master_.clear();
×
3700
    return new BLong( 0 );
×
3701

3702
    break;
3703
  }
3704
  default:
×
3705
    return nullptr;
×
3706
  }
3707
}
3708

3709
BObjectImp* NPC::script_method( const char* methodname, Core::UOExecutor& executor )
×
3710
{
3711
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
3712
  if ( objmethod != nullptr )
×
3713
    return this->script_method_id( objmethod->id, executor );
×
3714
  return nullptr;
×
3715
}
3716

3717
BObjectImp* NPC::custom_script_method( const char* methodname, Core::UOExecutor& executor )
×
3718
{
3719
  if ( template_->method_script != nullptr )
×
3720
  {
3721
    unsigned PC;
3722
    if ( template_->method_script->FindExportedFunction(
×
3723
             methodname, static_cast<unsigned int>( executor.numParams() + 1 ), PC ) )
×
3724
      return template_->method_script->call( PC, make_ref(), executor.fparams );
×
3725
  }
3726
  return Core::gamestate.system_hooks.call_script_method( methodname, &executor, this );
×
3727
}
3728
}  // namespace Mobile
3729
namespace Core
3730
{
3731
using namespace Bscript;
3732

3733
BObjectImp* ULockable::get_script_member_id( const int id ) const
254✔
3734
{
3735
  BObjectImp* imp = Item::get_script_member_id( id );
254✔
3736
  if ( imp != nullptr )
254✔
3737
    return imp;
201✔
3738

3739
  switch ( id )
53✔
3740
  {
3741
  case MBR_LOCKED:
1✔
3742
    return new BLong( locked() ? 1 : 0 );
1✔
3743
    break;
3744
  default:
52✔
3745
    return nullptr;
52✔
3746
  }
3747
}
3748

3749
BObjectImp* ULockable::get_script_member( const char* membername ) const
×
3750
{
3751
  ObjMember* objmember = getKnownObjMember( membername );
×
3752
  if ( objmember != nullptr )
×
3753
    return this->get_script_member_id( objmember->id );
×
3754
  return nullptr;
×
3755
}
3756

3757
BObjectImp* ULockable::set_script_member_id( const int id, int value )
61✔
3758
{
3759
  BObjectImp* imp = Item::set_script_member_id( id, value );
61✔
3760
  if ( imp != nullptr )
61✔
3761
    return imp;
48✔
3762
  switch ( id )
13✔
3763
  {
3764
  case MBR_LOCKED:
1✔
3765
    locked( value ? true : false );
1✔
3766
    return new BLong( locked() );
1✔
3767
  default:
12✔
3768
    return nullptr;
12✔
3769
  }
3770
}
3771

3772
BObjectImp* ULockable::set_script_member( const char* membername, int value )
×
3773
{
3774
  ObjMember* objmember = getKnownObjMember( membername );
×
3775
  if ( objmember != nullptr )
×
3776
    return this->set_script_member_id( objmember->id, value );
×
3777
  return nullptr;
×
3778
}
3779

3780
BObjectImp* UContainer::get_script_member_id( const int id ) const
228✔
3781
{
3782
  BObjectImp* imp = base::get_script_member_id( id );
228✔
3783
  if ( imp != nullptr )
228✔
3784
    return imp;
176✔
3785

3786
  switch ( id )
52✔
3787
  {
3788
  case MBR_MAX_ITEMS_MOD:
1✔
3789
    return new BLong( max_items_mod() );
1✔
3790
    break;
3791
  case MBR_MAX_WEIGHT_MOD:
1✔
3792
    return new BLong( max_weight_mod() );
1✔
3793
    break;
3794
  case MBR_MAX_SLOTS_MOD:
1✔
3795
    return new BLong( max_slots_mod() );
1✔
3796
    break;
3797
  case MBR_NO_DROP_EXCEPTION:
2✔
3798
    return new BLong( no_drop_exception() );
2✔
3799
  case MBR_HELD_WEIGHT_MULTIPLIER:
8✔
3800
    return new Double( held_weight_multiplier() );
8✔
3801
  default:
39✔
3802
    return nullptr;
39✔
3803
  }
3804
}
3805

3806
BObjectImp* UContainer::get_script_member( const char* membername ) const
6✔
3807
{
3808
  ObjMember* objmember = getKnownObjMember( membername );
6✔
3809
  if ( objmember != nullptr )
6✔
3810
    return this->get_script_member_id( objmember->id );
6✔
3811
  return nullptr;
×
3812
}
3813

3814
BObjectImp* UContainer::set_script_member_id( const int id, int value )
61✔
3815
{
3816
  BObjectImp* imp = base::set_script_member_id( id, value );
61✔
3817
  if ( imp != nullptr )
61✔
3818
    return imp;
49✔
3819
  switch ( id )
12✔
3820
  {
3821
  case MBR_MAX_ITEMS_MOD:
1✔
3822
    max_items_mod( Clib::clamp_convert<s16>( value ) );
1✔
3823
    break;
1✔
3824
  case MBR_MAX_WEIGHT_MOD:
1✔
3825
    max_weight_mod( Clib::clamp_convert<s16>( value ) );
1✔
3826
    break;
1✔
3827
  case MBR_MAX_SLOTS_MOD:
1✔
3828
    max_slots_mod( Clib::clamp_convert<s8>( value ) );
1✔
3829
    break;
1✔
3830
  case MBR_NO_DROP_EXCEPTION:
2✔
3831
    no_drop_exception( value ? true : false );
2✔
3832
    return new BLong( no_drop_exception() );
2✔
3833
  case MBR_WEIGHT_MULTIPLIER_MOD:
×
3834
    return set_script_member_id_double( id, value );
×
3835
  case MBR_HELD_WEIGHT_MULTIPLIER:
7✔
3836
    return set_script_member_id_double( id, value );
7✔
3837
  default:
×
3838
    return nullptr;
×
3839
  }
3840
  return new BLong( value );
3✔
3841
}
3842

3843
Bscript::BObjectImp* UContainer::set_script_member_id_double( const int id, double value )
13✔
3844
{
3845
  BObjectImp* imp = base::set_script_member_id_double( id, value );
13✔
3846
  if ( imp != nullptr )
13✔
3847
    return imp;
×
3848

3849
  switch ( id )
13✔
3850
  {
3851
  case MBR_HELD_WEIGHT_MULTIPLIER:
13✔
3852
  {
3853
    if ( container )
13✔
3854
    {
3855
      int oldweight = weight();
8✔
3856
      held_weight_multiplier( value );
8✔
3857
      container->add_bulk( 0, weight() - oldweight );
8✔
3858
    }
3859
    else
3860
    {
3861
      held_weight_multiplier( value );
5✔
3862
    }
3863

3864
    increv_send_object_recursive();
13✔
3865

3866
    UpdateCharacterWeight( this );
13✔
3867

3868
    return new Double( held_weight_multiplier() );
13✔
3869
  }
3870
  default:
×
3871
    break;
×
3872
  }
3873
  return nullptr;
×
3874
}
3875

3876
BObjectImp* UContainer::set_script_member( const char* membername, int value )
53✔
3877
{
3878
  ObjMember* objmember = getKnownObjMember( membername );
53✔
3879
  if ( objmember != nullptr )
53✔
3880
    return this->set_script_member_id( objmember->id, value );
53✔
3881
  return nullptr;
×
3882
}
3883

3884
BObjectImp* UCorpse::get_script_member_id( const int id ) const
46✔
3885
{
3886
  BObjectImp* imp = base::get_script_member_id( id );
46✔
3887
  if ( imp != nullptr )
46✔
3888
    return imp;
7✔
3889

3890
  switch ( id )
39✔
3891
  {
3892
  case MBR_CORPSETYPE:
1✔
3893
    return new BLong( corpsetype );
1✔
3894
    break;
3895
  case MBR_OWNERSERIAL:
38✔
3896
    return new BLong( ownerserial );
38✔
3897
    break;
3898
  default:
×
3899
    return nullptr;
×
3900
  }
3901
}
3902

3903
BObjectImp* UCorpse::get_script_member( const char* membername ) const
2✔
3904
{
3905
  ObjMember* objmember = getKnownObjMember( membername );
2✔
3906
  if ( objmember != nullptr )
2✔
3907
    return this->get_script_member_id( objmember->id );
2✔
3908
  return nullptr;
×
3909
}
3910

3911
BObjectImp* Spellbook::script_method_id( const int id, Core::UOExecutor& ex )
4✔
3912
{
3913
  BObjectImp* imp = base::script_method_id( id, ex );
4✔
3914
  if ( imp != nullptr )
4✔
3915
    return imp;
×
3916

3917
  switch ( id )
4✔
3918
  {
3919
  case MTH_HASSPELL:
2✔
3920
  {
3921
    u32 sid;
3922
    if ( !ex.hasParams( 1 ) )
2✔
3923
      return new BError( "Not enough parameters" );
2✔
3924
    if ( ex.getParam( 0, sid ) )
2✔
3925
    {
3926
      if ( sid == 0 )
2✔
3927
        return new BError( "SpellID must be >= 1" );
×
3928
      if ( this->has_spellid( sid ) )
2✔
3929
        return new BLong( 1 );
2✔
3930
      return new BLong( 0 );
×
3931
    }
3932
    break;
×
3933
  }
3934
  case MTH_SPELLS:
×
3935
  {
3936
    std::unique_ptr<ObjArray> arr( new ObjArray );
×
3937
    for ( u16 i = 0; i < 64; ++i )
×
3938
    {
3939
      unsigned int sid;
3940

3941
      // Check for Mysticism spells here
3942
      if ( this->spell_school == 3 )
×
3943
        sid = 678 + i;
×
3944
      else
3945
        sid = this->spell_school * 100 + i + 1;
×
3946

3947
      if ( this->has_spellid( sid ) )
×
3948
        arr->addElement( new BLong( sid ) );
×
3949
    }
3950
    return arr.release();
×
3951
    break;
3952
  }
×
3953
  case MTH_REMOVESPELL:
×
3954
  {
3955
    u32 sid;
3956
    if ( !ex.hasParams( 1 ) )
×
3957
      return new BError( "Not enough parameters" );
×
3958
    if ( ex.getParam( 0, sid ) )
×
3959
    {
3960
      if ( sid == 0 )
×
3961
        return new BError( "SpellID must be >= 1" );
×
3962
      if ( this->remove_spellid( sid ) )
×
3963
        return new BLong( 1 );
×
3964
      return new BLong( 0 );
×
3965
    }
3966
    break;
×
3967
  }
3968
  case MTH_ADDSPELL:
2✔
3969
  {
3970
    u32 sid;
3971
    if ( !ex.hasParams( 1 ) )
2✔
3972
      return new BError( "Not enough parameters" );
2✔
3973
    if ( ex.getParam( 0, sid ) )
2✔
3974
    {
3975
      if ( sid == 0 )
2✔
3976
        return new BError( "SpellID must be >= 1" );
×
3977
      if ( this->add_spellid( sid ) )
2✔
3978
        return new BLong( 1 );
2✔
3979
      return new BLong( 0 );
×
3980
    }
3981
    break;
×
3982
  }
3983

3984
  default:
×
3985
    return nullptr;
×
3986
  }
3987
  return new BError( "Invalid parameter type" );
×
3988
}
3989

3990
BObjectImp* Spellbook::script_method( const char* methodname, Core::UOExecutor& ex )
×
3991
{
3992
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
3993
  if ( objmethod != nullptr )
×
3994
    return this->script_method_id( objmethod->id, ex );
×
3995
  return nullptr;
×
3996
}
3997
}  // namespace Core
3998
namespace Multi
3999
{
4000
using namespace Bscript;
4001

4002
BObjectImp* UBoat::make_ref()
5✔
4003
{
4004
  return new Module::EUBoatRefObjImp( this );
5✔
4005
}
4006

4007
BObjectImp* UMulti::make_ref()
23✔
4008
{
4009
  return new Module::EMultiRefObjImp( this );
23✔
4010
}
4011

4012
BObjectImp* UBoat::get_script_member_id( const int id ) const
6,159✔
4013
{
4014
  BObjectImp* imp = base::get_script_member_id( id );
6,159✔
4015
  if ( imp != nullptr )
6,159✔
4016
    return imp;
6,122✔
4017

4018
  switch ( id )
37✔
4019
  {
4020
  case MBR_TILLERMAN:
×
4021
  {
4022
    Item* cp = tillerman;
×
4023
    if ( cp != nullptr )
×
4024
      return new Module::EItemRefObjImp( cp );
×
4025
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4026
    break;
4027
  }
4028
  case MBR_PORTPLANK:
20✔
4029
  {
4030
    Item* cp = portplank;
20✔
4031
    if ( cp != nullptr )
20✔
4032
      return new Module::EItemRefObjImp( cp );
20✔
4033
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4034
    break;
4035
  }
4036
  case MBR_STARBOARDPLANK:
×
4037
  {
4038
    Item* cp = starboardplank;
×
4039
    if ( cp != nullptr )
×
4040
      return new Module::EItemRefObjImp( cp );
×
4041
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4042
    break;
4043
  }
4044
  case MBR_HOLD:
×
4045
  {
4046
    Item* cp = hold;
×
4047
    if ( cp != nullptr )
×
4048
      return new Module::EItemRefObjImp( cp );
×
4049
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4050
    break;
4051
  }
4052
  case MBR_ROPE:
×
4053
    return component_list( COMPONENT_ROPE );
×
4054
    break;
4055
  case MBR_WHEEL:
×
4056
    return component_list( COMPONENT_WHEEL );
×
4057
    break;
4058
  case MBR_HULL:
×
4059
    return component_list( COMPONENT_HULL );
×
4060
    break;
4061
  case MBR_TILLER:
×
4062
    return component_list( COMPONENT_TILLER );
×
4063
    break;
4064
  case MBR_RUDDER:
×
4065
    return component_list( COMPONENT_RUDDER );
×
4066
    break;
4067
  case MBR_SAILS:
×
4068
    return component_list( COMPONENT_SAILS );
×
4069
    break;
4070
  case MBR_STORAGE:
×
4071
    return component_list( COMPONENT_STORAGE );
×
4072
    break;
4073
  case MBR_WEAPONSLOT:
×
4074
    return component_list( COMPONENT_WEAPONSLOT );
×
4075
    break;
4076
  case MBR_COMPONENTS:
1✔
4077
    return component_list( COMPONENT_ALL );
1✔
4078
    break;
4079
  case MBR_ITEMS:
3✔
4080
    return items_list();
3✔
4081
    break;
4082
  case MBR_MOBILES:
4✔
4083
    return mobiles_list();
4✔
4084
    break;
4085
  case MBR_HAS_OFFLINE_MOBILES:
×
4086
    return new BLong( has_offline_mobiles() ? 1 : 0 );
×
4087
    break;
4088
  case MBR_MULTIID:
6✔
4089
    return new BLong( multiid_ );
6✔
4090
    break;
4091
  case MBR_PILOT:
3✔
4092
  {
4093
    Mobile::Character* owner = pilot();
3✔
4094
    if ( owner != nullptr )
3✔
4095
    {
4096
      return new Module::ECharacterRefObjImp( owner );
2✔
4097
    }
4098
  }
4099
    return new BLong( 0 );
1✔
4100
  default:
×
4101
    return nullptr;
×
4102
  }
4103
}
4104

4105
BObjectImp* UBoat::get_script_member( const char* membername ) const
2✔
4106
{
4107
  ObjMember* objmember = getKnownObjMember( membername );
2✔
4108
  if ( objmember != nullptr )
2✔
4109
    return this->get_script_member_id( objmember->id );
2✔
4110
  return nullptr;
×
4111
}
4112

4113
BObjectImp* UBoat::script_method_id( const int id, Core::UOExecutor& ex )
43✔
4114
{
4115
  BObjectImp* imp = base::script_method_id( id, ex );
43✔
4116
  if ( imp != nullptr )
43✔
4117
    return imp;
29✔
4118

4119
  switch ( id )
14✔
4120
  {
4121
  case MTH_MOVE_OFFLINE_MOBILES:
×
4122
  {
4123
    if ( ex.numParams() == 3 )
×
4124
    {
4125
      Core::Pos3d pos;
×
4126
      if ( !ex.getPos3dParam( 0, 1, 2, &pos, realm() ) )
×
4127
        return new BError( "Invalid parameter type" );
×
4128
      set_dirty();
×
4129
      move_offline_mobiles( Core::Pos4d( pos, realm() ) );
×
4130
      return new BLong( 1 );
×
4131
    }
4132
    if ( ex.numParams() == 4 )
×
4133
    {
4134
      Core::Pos4d pos;
×
4135
      if ( !ex.getPos4dParam( 0, 1, 2, 3, &pos ) )
×
4136
        return new BError( "Invalid parameter type" );
×
4137
      set_dirty();
×
4138
      move_offline_mobiles( pos );
×
4139
      return new BLong( 1 );
×
4140
    }
4141
    return new BError( "Not enough parameters" );
×
4142
  }
4143
  case MTH_SET_PILOT:
10✔
4144
  {
4145
    if ( !ex.hasParams( 1 ) )
10✔
4146
    {
4147
      return new BError( "Not enough parameters" );
×
4148
    }
4149

4150
    BObjectImp* impMaybeZero = ex.getParamImp( 0 );
10✔
4151

4152
    if ( auto* value = impptrIf<BLong>( impMaybeZero ) )
10✔
4153
    {
4154
      if ( value->value() != 0 )
6✔
4155
        return new BError( "Invalid parameters" );
×
4156
      return set_pilot( nullptr );
6✔
4157
    }
4158

4159
    Mobile::Character* chr;
4160

4161
    if ( !ex.getCharacterParam( 0, chr ) )
4✔
4162
      return new BError( "Invalid parameters" );
×
4163

4164
    return set_pilot( chr );
4✔
4165
  }
4166
  case MTH_SET_ALTERNATE_MULTIID:
4✔
4167
  {
4168
    if ( ex.numParams() != 1 )
4✔
4169
      return new BError( "Not enough parameters" );
×
4170
    u32 index;
4171
    if ( !ex.getParam( 0, index ) )
4✔
4172
      return new BError( "Invalid parameter type" );
×
4173
    const auto& desc = static_cast<const Items::BoatDesc&>( itemdesc() );
4✔
4174
    if ( index >= desc.alternates.size() )
4✔
4175
      return new BError( "Index out of range" );
1✔
4176

4177
    {
4178
      UBoat::BoatMoveGuard guard( this );
3✔
4179
      u16 new_multiid = desc.alternates[index];
3✔
4180
      u16 base_multi = multiid_ & ~3u;
3✔
4181
      u16 multioffset = multiid_ - base_multi;
3✔
4182
      multiid_ = new_multiid + multioffset;
3✔
4183
    }
3✔
4184
    transform_components( boatshape() );
3✔
4185
    send_display_boat_to_inrange( {} );
3✔
4186
    return new BLong( 1 );
3✔
4187
  }
4188
  default:
×
4189
    return nullptr;
×
4190
  }
4191
}
4192

4193
BObjectImp* UBoat::script_method( const char* methodname, Core::UOExecutor& ex )
×
4194
{
4195
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4196
  if ( objmethod != nullptr )
×
4197
    return this->script_method_id( objmethod->id, ex );
×
4198
  return nullptr;
×
4199
}
4200

4201
BObjectImp* UPlank::get_script_member_id( const int id ) const
20✔
4202
{
4203
  switch ( id )
20✔
4204
  {
4205
  case MBR_MULTI:
×
4206
    if ( boat_.get() )
×
4207
      return new Module::EUBoatRefObjImp( boat_.get() );
×
4208
    return new BError( "No boat attached" );
×
4209
    break;
4210
  }
4211
  return base::get_script_member_id( id );
20✔
4212
}
4213

4214
/* UObject defines a 'multi' also, so we have to trap that here first */
4215
BObjectImp* UPlank::get_script_member( const char* membername ) const
×
4216
{
4217
  ObjMember* objmember = getKnownObjMember( membername );
×
4218
  if ( objmember != nullptr )
×
4219
    return this->get_script_member_id( objmember->id );
×
4220
  return base::get_script_member( membername );
×
4221
}
4222
}  // namespace Multi
4223
namespace Core
4224
{
4225
using namespace Bscript;
4226

4227
BObjectImp* Map::get_script_member_id( const int id ) const
9✔
4228
{
4229
  BObjectImp* imp = base::get_script_member_id( id );
9✔
4230
  if ( imp != nullptr )
9✔
4231
    return imp;
1✔
4232

4233
  switch ( id )
8✔
4234
  {
4235
  case MBR_XEAST:
1✔
4236
    return new BLong( xeast );
1✔
4237
  case MBR_XWEST:
1✔
4238
    return new BLong( xwest );
1✔
4239
  case MBR_YNORTH:
1✔
4240
    return new BLong( ynorth );
1✔
4241
  case MBR_YSOUTH:
1✔
4242
    return new BLong( ysouth );
1✔
4243
  case MBR_GUMPWIDTH:
1✔
4244
    return new BLong( gumpsize.x() );
1✔
4245
  case MBR_GUMPHEIGHT:
1✔
4246
    return new BLong( gumpsize.y() );
1✔
4247
  case MBR_FACETID:
1✔
4248
    return new BLong( facetid );
1✔
4249
  case MBR_EDITABLE:
1✔
4250
    return new BLong( editable ? 1 : 0 );
1✔
4251
  default:
×
4252
    return nullptr;
×
4253
  }
4254
}
4255

4256
BObjectImp* Map::get_script_member( const char* membername ) const
8✔
4257
{
4258
  ObjMember* objmember = getKnownObjMember( membername );
8✔
4259
  if ( objmember != nullptr )
8✔
4260
    return this->get_script_member_id( objmember->id );
8✔
4261
  return nullptr;
×
4262
}
4263

4264
BObjectImp* Map::set_script_member_id( const int id, int value )
8✔
4265
{
4266
  BObjectImp* imp = base::set_script_member_id( id, value );
8✔
4267
  if ( imp != nullptr )
8✔
4268
    return imp;
×
4269
  switch ( id )
8✔
4270
  {
4271
  case MBR_XEAST:
1✔
4272
    return new BLong( xeast = Clib::clamp_convert<u16>( value ) );
1✔
4273
  case MBR_XWEST:
1✔
4274
    return new BLong( xwest = Clib::clamp_convert<u16>( value ) );
1✔
4275
  case MBR_YNORTH:
1✔
4276
    return new BLong( ynorth = Clib::clamp_convert<u16>( value ) );
1✔
4277
  case MBR_YSOUTH:
1✔
4278
    return new BLong( ysouth = Clib::clamp_convert<u16>( value ) );
1✔
4279
  case MBR_GUMPWIDTH:
1✔
4280
    gumpsize.x( Clib::clamp_convert<u16>( value ) );
1✔
4281
    return new BLong( gumpsize.x() );
1✔
4282
  case MBR_GUMPHEIGHT:
1✔
4283
    gumpsize.y( Clib::clamp_convert<u16>( value ) );
1✔
4284
    return new BLong( gumpsize.y() );
1✔
4285
  case MBR_FACETID:
1✔
4286
    return new BLong( facetid = Clib::clamp_convert<u16>( value ) );
1✔
4287
  case MBR_EDITABLE:
1✔
4288
    return new BLong( editable = value ? true : false );
1✔
4289
  default:
×
4290
    return nullptr;
×
4291
  }
4292
}
4293
BObjectImp* Map::set_script_member( const char* membername, int value )
8✔
4294
{
4295
  ObjMember* objmember = getKnownObjMember( membername );
8✔
4296
  if ( objmember != nullptr )
8✔
4297
    return this->set_script_member_id( objmember->id, value );
8✔
4298
  return nullptr;
×
4299
}
4300

4301
BObjectImp* UObject::script_method_id( const int id, Core::UOExecutor& ex )
676✔
4302
{
4303
  switch ( id )
676✔
4304
  {
4305
  case MTH_ISA:
×
4306
  {
4307
    if ( !ex.hasParams( 1 ) )
×
4308
      return new BError( "Not enough parameters" );
×
4309
    u32 isatype;
4310
    if ( ex.getParam( 0, isatype ) )
×
4311
      return new BLong( script_isa( isatype ) );
×
4312
    break;
×
4313
  }
4314
  case MTH_SET_MEMBER:
189✔
4315
  {
4316
    if ( !ex.hasParams( 2 ) )
189✔
4317
      return new BError( "Not enough parameters" );
189✔
4318
    BObjectImp* objimp;
4319
    const String* mname;
4320
    if ( ex.getStringParam( 0, mname ) && ( objimp = ex.getParamImp( 1 ) ) != nullptr )
189✔
4321
    {
4322
      BObjectImp* ret;
4323
      if ( auto* l = impptrIf<BLong>( objimp ) )
189✔
4324
        ret = set_script_member( mname->value().c_str(), l->value() );
170✔
4325
      else if ( auto* d = impptrIf<Double>( objimp ) )
19✔
4326
        ret = set_script_member_double( mname->value().c_str(), d->value() );
6✔
4327
      else if ( auto* s = impptrIf<String>( objimp ) )
13✔
4328
        ret = set_script_member( mname->value().c_str(), s->value() );
13✔
4329
      else
4330
        return new BError( "Invalid value type" );
×
4331

4332
      if ( ret != nullptr )
189✔
4333
        return ret;
189✔
4334

4335
      std::string message = std::string( "Member " ) + std::string( mname->value() ) +
×
4336
                            std::string( " not found on that object" );
×
4337
      return new BError( message );
×
4338
    }
×
4339
    break;
×
4340
  }
4341
  case MTH_GET_MEMBER:
273✔
4342
  {
4343
    if ( !ex.hasParams( 1 ) )
273✔
4344
      return new BError( "Not enough parameters" );
273✔
4345

4346
    const String* mname;
4347
    if ( ex.getStringParam( 0, mname ) )
273✔
4348
    {
4349
      BObjectImp* ret = get_script_member( mname->value().c_str() );
273✔
4350
      if ( ret != nullptr )
273✔
4351
        return ret;
273✔
4352

4353
      std::string message = std::string( "Member " ) + std::string( mname->value() ) +
×
4354
                            std::string( " not found on that object" );
×
4355
      return new BError( message );
×
4356
    }
×
4357
    break;
×
4358
  }
4359
  default:
214✔
4360
  {
4361
    bool changed = false;
214✔
4362
    BObjectImp* imp = CallPropertyListMethod_id( proplist_, id, ex, changed );
214✔
4363
    if ( changed )
214✔
4364
      set_dirty();
46✔
4365
    return imp;
214✔
4366
  }
4367
  }
4368
  return new BError( "Invalid parameter type" );
×
4369
}
4370

4371

4372
BObjectImp* UObject::script_method( const char* methodname, Core::UOExecutor& ex )
×
4373
{
4374
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4375
  if ( objmethod != nullptr )
×
4376
    return this->script_method_id( objmethod->id, ex );
×
4377

4378
  bool changed = false;
×
4379
  BObjectImp* imp = CallPropertyListMethod( proplist_, methodname, ex, changed );
×
4380
  if ( changed )
×
4381
    set_dirty();
×
4382

4383
  return imp;
×
4384
}
4385

4386
BObjectImp* UObject::custom_script_method( const char* methodname, Core::UOExecutor& ex )
×
4387
{
4388
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4389
  if ( objmethod != nullptr )
×
4390
    return this->script_method_id( objmethod->id, ex );
×
4391
  return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
×
4392
}
4393

4394
BObjectImp* UDoor::get_script_member_id( const int id ) const
6✔
4395
{
4396
  BObjectImp* imp = ULockable::get_script_member_id( id );
6✔
4397
  if ( imp != nullptr )
6✔
4398
    return imp;
6✔
4399

4400
  switch ( id )
×
4401
  {
4402
  case MBR_ISOPEN:
×
4403
    return new BLong( is_open() ? 1 : 0 );
×
4404
    break;
4405
  default:
×
4406
    return nullptr;
×
4407
  }
4408
}
4409

4410
BObjectImp* UDoor::get_script_member( const char* membername ) const
×
4411
{
4412
  ObjMember* objmember = getKnownObjMember( membername );
×
4413
  if ( objmember != nullptr )
×
4414
    return this->get_script_member_id( objmember->id );
×
4415
  return nullptr;
×
4416
}
4417

4418
BObjectImp* UDoor::script_method_id( const int id, Core::UOExecutor& ex )
×
4419
{
4420
  BObjectImp* imp = base::script_method_id( id, ex );
×
4421
  if ( imp != nullptr )
×
4422
    return imp;
×
4423

4424
  switch ( id )
×
4425
  {
4426
  case MTH_OPEN:
×
4427
    open();
×
4428
    break;
×
4429
  case MTH_CLOSE:
×
4430
    close();
×
4431
    break;
×
4432
  case MTH_TOGGLE:
×
4433
    toggle();
×
4434
    break;
×
4435
  default:
×
4436
    return nullptr;
×
4437
  }
4438
  return new BLong( 1 );
×
4439
}
4440

4441
BObjectImp* UDoor::script_method( const char* methodname, Core::UOExecutor& ex )
×
4442
{
4443
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4444
  if ( objmethod != nullptr )
×
4445
    return this->script_method_id( objmethod->id, ex );
×
4446
  return nullptr;
×
4447
}
4448
}  // namespace Core
4449
namespace Items
4450
{
4451
using namespace Bscript;
4452

4453
BObjectImp* Equipment::get_script_member_id( const int id ) const
9✔
4454
{
4455
  BObjectImp* imp = Item::get_script_member_id( id );
9✔
4456
  if ( imp != nullptr )
9✔
4457
    return imp;
4✔
4458

4459
  switch ( id )
5✔
4460
  {
4461
  case MBR_INTRINSIC:
×
4462
    return new BLong( is_intrinsic() );
×
4463
    break;
4464
  default:
5✔
4465
    return nullptr;
5✔
4466
  }
4467
}
4468
BObjectImp* Equipment::get_script_member( const char* membername ) const
×
4469
{
4470
  ObjMember* objmember = getKnownObjMember( membername );
×
4471
  if ( objmember != nullptr )
×
4472
    return this->get_script_member_id( objmember->id );
×
4473
  return nullptr;
×
4474
}
4475

4476
BObjectImp* Equipment::set_script_member_id( const int id, int value )
3✔
4477
{
4478
  BObjectImp* imp = Item::set_script_member_id( id, value );
3✔
4479
  if ( imp != nullptr )
3✔
4480
    return imp;
×
4481

4482
  return nullptr;
3✔
4483
  /*
4484
  switch(id)
4485
  {
4486
  default: return nullptr;
4487
  }
4488
  */
4489
}
4490
BObjectImp* Equipment::set_script_member( const char* membername, int value )
×
4491
{
4492
  ObjMember* objmember = getKnownObjMember( membername );
×
4493
  if ( objmember != nullptr )
×
4494
    return this->set_script_member_id( objmember->id, value );
×
4495
  return nullptr;
×
4496
}
4497

4498
BObjectImp* Equipment::set_script_member_id_double( const int id, double value )
×
4499
{
4500
  BObjectImp* imp = Item::set_script_member_id_double( id, value );
×
4501
  if ( imp != nullptr )
×
4502
    return imp;
×
4503

4504
  return nullptr;
×
4505
  /*
4506
  switch(id)
4507
  {
4508
  default: return nullptr;
4509
  }
4510
  */
4511
}
4512
BObjectImp* Equipment::set_script_member_double( const char* membername, double value )
×
4513
{
4514
  ObjMember* objmember = getKnownObjMember( membername );
×
4515
  if ( objmember != nullptr )
×
4516
    return this->set_script_member_id_double( objmember->id, value );
×
4517
  return nullptr;
×
4518
}
4519

4520

4521
BObjectImp* UWeapon::get_script_member_id( const int id ) const
4✔
4522
{
4523
  BObjectImp* imp = Equipment::get_script_member_id( id );
4✔
4524
  if ( imp != nullptr )
4✔
4525
    return imp;
1✔
4526

4527
  switch ( id )
3✔
4528
  {
4529
  case MBR_DMG_MOD:
1✔
4530
    return new BLong( damage_mod() );
1✔
4531
    break;
4532
  case MBR_SPEED_MOD:
1✔
4533
    return new BLong( speed_mod() );
1✔
4534
    break;
4535
  case MBR_ATTRIBUTE:
×
4536
    return new String( attribute().name );
×
4537
    break;
4538
  case MBR_HITSCRIPT:
1✔
4539
    return new String( hit_script_.qualifiedname() );
1✔
4540
    break;
4541
  default:
×
4542
    return nullptr;
×
4543
  }
4544
}
4545
BObjectImp* UWeapon::get_script_member( const char* membername ) const
3✔
4546
{
4547
  ObjMember* objmember = getKnownObjMember( membername );
3✔
4548
  if ( objmember != nullptr )
3✔
4549
    return this->get_script_member_id( objmember->id );
3✔
4550
  return nullptr;
×
4551
}
4552

4553
BObjectImp* UWeapon::set_script_member_id( const int id, const std::string& value )
2✔
4554
{
4555
  BObjectImp* imp = Item::set_script_member_id( id, value );
2✔
4556
  if ( imp != nullptr )
2✔
4557
    return imp;
1✔
4558

4559
  switch ( id )
1✔
4560
  {
4561
  case MBR_HITSCRIPT:
1✔
4562
    set_hit_script( value );
1✔
4563
    return new BLong( 1 );
1✔
4564
  default:
×
4565
    return nullptr;
×
4566
  }
4567
}
4568
BObjectImp* UWeapon::set_script_member( const char* membername, const std::string& value )
1✔
4569
{
4570
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4571
  if ( objmember != nullptr )
1✔
4572
    return this->set_script_member_id( objmember->id, value );
1✔
4573
  return nullptr;
×
4574
}
4575

4576
BObjectImp* UWeapon::set_script_member_id( const int id, int value )
2✔
4577
{
4578
  if ( is_intrinsic() )
2✔
4579
    return new BError( "Cannot alter an instrinsic NPC weapon member values" );  // executor won't
×
4580
                                                                                 // return this to
4581
                                                                                 // the script
4582
                                                                                 // currently.
4583

4584
  BObjectImp* imp = Equipment::set_script_member_id( id, value );
2✔
4585
  if ( imp != nullptr )
2✔
4586
    return imp;
×
4587

4588
  switch ( id )
2✔
4589
  {
4590
  case MBR_DMG_MOD:
1✔
4591
    damage_mod( Clib::clamp_convert<s16>( value ) );
1✔
4592
    break;
1✔
4593
  case MBR_SPEED_MOD:
1✔
4594
    speed_mod( Clib::clamp_convert<s16>( value ) );
1✔
4595
    break;
1✔
4596
  default:
×
4597
    return nullptr;
×
4598
  }
4599
  return new BLong( value );
2✔
4600
}
4601

4602
BObjectImp* UWeapon::set_script_member( const char* membername, int value )
2✔
4603
{
4604
  ObjMember* objmember = getKnownObjMember( membername );
2✔
4605
  if ( objmember != nullptr )
2✔
4606
    return this->set_script_member_id( objmember->id, value );
2✔
4607
  return nullptr;
×
4608
}
4609

4610
BObjectImp* UWeapon::set_script_member_id_double( const int id, double value )
×
4611
{
4612
  if ( is_intrinsic() )
×
4613
    return new BError( "Cannot alter an instrinsic NPC weapon member values" );  // executor won't
×
4614
                                                                                 // return this to
4615
                                                                                 // the script
4616
                                                                                 // currently.
4617
  return base::set_script_member_id_double( id, value );
×
4618
}
4619

4620
BObjectImp* UWeapon::set_script_member_double( const char* membername, double value )
×
4621
{
4622
  ObjMember* objmember = getKnownObjMember( membername );
×
4623
  if ( objmember != nullptr )
×
4624
    return this->set_script_member_id_double( objmember->id, value );
×
4625
  return base::set_script_member_double( membername, value );
×
4626
}
4627

4628
BObjectImp* UArmor::get_script_member_id( const int id ) const
5✔
4629
{
4630
  BObjectImp* imp = Equipment::get_script_member_id( id );
5✔
4631
  if ( imp != nullptr )
5✔
4632
    return imp;
3✔
4633

4634
  switch ( id )
2✔
4635
  {
4636
  case MBR_AR_MOD:
1✔
4637
    return new BLong( ar_mod() );
1✔
4638
    break;
4639
  case MBR_AR:
×
4640
    return new BLong( ar() );
×
4641
    break;
4642
  case MBR_AR_BASE:
×
4643
    return new BLong( ar_base() );
×
4644
    break;
4645
  case MBR_ONHIT_SCRIPT:
1✔
4646
    // bad method name? nullptr makes it return the fullpath
4647
    return new String( onhitscript_.qualifiedname() );
1✔
4648
    break;
4649
  default:
×
4650
    return nullptr;
×
4651
  }
4652
}
4653

4654
BObjectImp* UArmor::get_script_member( const char* membername ) const
2✔
4655
{
4656
  ObjMember* objmember = getKnownObjMember( membername );
2✔
4657
  if ( objmember != nullptr )
2✔
4658
    return this->get_script_member_id( objmember->id );
2✔
4659
  return nullptr;
×
4660
}
4661

4662
BObjectImp* UArmor::set_script_member_id( const int id, const std::string& value )
2✔
4663
{
4664
  BObjectImp* imp = Item::set_script_member_id( id, value );
2✔
4665
  if ( imp != nullptr )
2✔
4666
    return imp;
1✔
4667
  switch ( id )
1✔
4668
  {
4669
  case MBR_ONHIT_SCRIPT:
1✔
4670
    set_onhitscript( value );
1✔
4671
    return new BLong( 1 );
1✔
4672
  default:
×
4673
    return nullptr;
×
4674
  }
4675
}
4676

4677
BObjectImp* UArmor::set_script_member( const char* membername, const std::string& value )
1✔
4678
{
4679
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4680
  if ( objmember != nullptr )
1✔
4681
    return this->set_script_member_id( objmember->id, value );
1✔
4682
  return nullptr;
×
4683
}
4684

4685
BObjectImp* UArmor::set_script_member_id( const int id, int value )
1✔
4686
{
4687
  BObjectImp* imp = Equipment::set_script_member_id( id, value );
1✔
4688
  if ( imp != nullptr )
1✔
4689
    return imp;
×
4690

4691
  switch ( id )
1✔
4692
  {
4693
  case MBR_AR_MOD:
1✔
4694
    this->ar_mod( Clib::clamp_convert<s16>( value ) );
1✔
4695
    if ( container != nullptr )
1✔
4696
    {
4697
      if ( Core::IsCharacter( container->serial ) )
×
4698
      {
4699
        Mobile::Character* chr = container->get_chr_owner();
×
4700
        if ( chr != nullptr )
×
4701
          Mobile::ARUpdater::on_change( chr );
×
4702
      }
4703
    }
4704
    return new BLong( value );
1✔
4705
  default:
×
4706
    return nullptr;
×
4707
  }
4708
}
4709

4710
BObjectImp* UArmor::set_script_member( const char* membername, int value )
1✔
4711
{
4712
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4713
  if ( objmember != nullptr )
1✔
4714
    return this->set_script_member_id( objmember->id, value );
1✔
4715
  return nullptr;
×
4716
}
4717
}  // namespace Items
4718
namespace Module
4719
{
4720
using namespace Bscript;
4721

4722
const char* EClientRefObjImp::typeOf() const
×
4723
{
4724
  return "ClientRef";
×
4725
}
4726

4727
u8 EClientRefObjImp::typeOfInt() const
×
4728
{
4729
  return OTClientRef;
×
4730
}
4731

4732
BObjectImp* EClientRefObjImp::copy() const
×
4733
{
4734
  if ( value().exists() )
×
4735
    return value()->make_ref();
×
4736
  return new BError( "Client is disconnected" );
×
4737
}
4738

4739
bool EClientRefObjImp::isTrue() const
2✔
4740
{
4741
  return ( value().exists() && value()->isConnected() );
2✔
4742
}
4743

4744
bool EClientRefObjImp::operator==( const BObjectImp& objimp ) const
×
4745
{
4746
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
×
4747
  {
4748
    const BApplicObjBase* aob =
4749
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
×
4750

4751
    if ( aob->object_type() == &eclientrefobjimp_type )
×
4752
    {
4753
      const EClientRefObjImp* clientref_imp =
4754
          Clib::explicit_cast<const EClientRefObjImp*, const BApplicObjBase*>( aob );
×
4755

4756
      if ( clientref_imp->value().exists() && value().exists() &&
×
4757
           ( clientref_imp->value()->chr != nullptr ) && ( value()->chr != nullptr ) )
×
4758
        return ( clientref_imp->value()->chr->serial == value()->chr->serial );
×
4759
      return false;
×
4760
    }
4761
    return false;
×
4762
  }
4763
  if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
×
4764
    return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
×
4765
  return false;
×
4766
}
4767

4768
BObjectRef EClientRefObjImp::get_member_id( const int id )
5✔
4769
{
4770
  if ( ( !obj_.exists() ) || ( !obj_->isConnected() ) )
5✔
4771
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4772

4773
  BObjectImp* result = obj_->get_script_member_id( id );
5✔
4774
  if ( result != nullptr )
5✔
4775
    return BObjectRef( result );
4✔
4776
  return BObjectRef( UninitObject::create() );
1✔
4777
}
4778

4779
BObjectRef EClientRefObjImp::get_member( const char* membername )
1✔
4780
{
4781
  if ( ( !obj_.exists() ) || ( !obj_->isConnected() ) )
1✔
4782
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4783
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4784
  if ( objmember != nullptr )
1✔
4785
    return this->get_member_id( objmember->id );
×
4786
  return BObjectRef( UninitObject::create() );
1✔
4787
}
4788

4789
BObjectRef EClientRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
×
4790
{
4791
  if ( !obj_.exists() || !obj_->isConnected() )
×
4792
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4793
  ObjMember* objmember = getKnownObjMember( membername );
×
4794
  if ( objmember != nullptr )
×
4795
    return this->set_member_id( objmember->id, value, copy );
×
4796
  return BObjectRef( UninitObject::create() );
×
4797
}
4798

4799
BObjectRef EClientRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
2✔
4800
{
4801
  if ( !obj_.exists() || !obj_->isConnected() )
2✔
4802
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4803

4804
  BObjectImp* result = nullptr;
2✔
4805
  if ( auto* v = impptrIf<BLong>( value ) )
2✔
4806
    result = obj_->set_script_member_id( id, v->value() );
2✔
4807

4808
  if ( result != nullptr )
2✔
4809
    return BObjectRef( result );
2✔
4810

4811
  return BObjectRef( UninitObject::create() );
×
4812
}
4813

4814

4815
BObjectImp* EClientRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
×
4816
{
4817
  if ( !obj_.exists() || !obj_->isConnected() )
×
4818
    return new BError( "Client not ready or disconnected" );
×
4819
  bool forcebuiltin{ Executor::builtinMethodForced( methodname ) };
×
4820
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4821
  if ( objmethod != nullptr )
×
4822
    return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
×
4823
  return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
×
4824
}
4825

4826
BObjectImp* EClientRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
×
4827
                                                 bool forcebuiltin )
4828
{
4829
  if ( !obj_.exists() || !obj_->isConnected() )
×
4830
    return new BError( "Client not ready or disconnected" );
×
4831

4832
  ObjMethod* mth = getObjMethod( id );
×
4833
  if ( mth->overridden && !forcebuiltin )
×
4834
  {
4835
    auto* imp = Core::gamestate.system_hooks.call_script_method( mth->code, &ex, this );
×
4836
    if ( imp )
×
4837
      return imp;
×
4838
  }
4839
  switch ( id )
×
4840
  {
4841
  case MTH_COMPAREVERSION:
×
4842
  {
4843
    if ( !ex.hasParams( 1 ) )
×
4844
      return new BError( "Not enough parameters" );
×
4845
    const String* pstr;
4846
    if ( ex.getStringParam( 0, pstr ) )
×
4847
      return new BLong( obj_->compareVersion( pstr->getStringRep() ) ? 1 : 0 );
×
4848
    return new BError( "Invalid parameter type" );
×
4849
  }
4850
  }
4851

4852
  return base::call_polmethod_id( id, ex );
×
4853
}
4854

4855
BoatMovementEvent::BoatMovementEvent( Mobile::Character* source, const u8 speed, const u8 direction,
3✔
4856
                                      const u8 relative_direction )
3✔
4857
{
4858
  addMember( "type", new BLong( Core::EVID_BOAT_MOVEMENT ) );
3✔
4859
  addMember( "source", new Module::EOfflineCharacterRefObjImp( source ) );
3✔
4860
  addMember( "speed", new BLong( static_cast<int>( speed ) ) );
3✔
4861
  addMember( "direction", new BLong( static_cast<int>( direction ) ) );
3✔
4862
  addMember( "relative_direction", new BLong( static_cast<int>( relative_direction ) ) );
3✔
4863
}
3✔
4864

4865
SourcedEvent::SourcedEvent( Core::EVENTID type, Core::UObject* source )
26✔
4866
{
4867
  addMember( "type", new BLong( type ) );
26✔
4868
  if ( source->ismobile() )
26✔
4869
    addMember( "source", static_cast<Mobile::Character*>( source )->make_offline_ref() );
26✔
4870
  else
NEW
4871
    addMember( "source", source->make_ref() );
×
4872
}
26✔
4873

4874
SpeechEvent::SpeechEvent( Mobile::Character* speaker, const std::string& speech,
3✔
4875
                          const std::string& texttype, std::string lang,
4876
                          Bscript::ObjArray* speechtokens )
3✔
4877
{
4878
  addMember( "type", new BLong( Core::EVID_SPOKE ) );
3✔
4879
  addMember( "source", new Module::EOfflineCharacterRefObjImp( speaker ) );
3✔
4880
  addMember( "text", new String( speech ) );
3✔
4881
  addMember( "texttype", new String( texttype ) );
3✔
4882
  if ( !lang.empty() )
3✔
4883
    addMember( "langcode", new String( lang ) );
3✔
4884
  if ( speechtokens != nullptr )
3✔
4885
    addMember( "tokens", new Bscript::ObjArray( *speechtokens ) );
3✔
4886
}
3✔
4887

4888
DamageEvent::DamageEvent( Mobile::Character* source, unsigned short damage )
×
4889
{
4890
  addMember( "type", new BLong( Core::EVID_DAMAGED ) );
×
4891

4892
  if ( source != nullptr )
×
4893
    addMember( "source", new Module::EOfflineCharacterRefObjImp( source ) );
×
4894
  else
4895
    addMember( "source", new BLong( 0 ) );
×
4896

4897
  addMember( "damage", new BLong( damage ) );
×
4898
}
×
4899

4900
ItemGivenEvent::ItemGivenEvent( Mobile::Character* chr_givenby, Items::Item* item_given,
×
4901
                                Mobile::NPC* chr_givento )
×
4902
    : SourcedEvent( Core::EVID_ITEM_GIVEN, chr_givenby ), given_by_( nullptr )
×
4903
{
4904
  addMember( "item", new EItemRefObjImp( item_given ) );
×
4905

4906
  given_time_ = Core::read_gameclock();
×
4907
  item_.set( item_given );
×
4908
  cont_.set( item_given->container );
×
4909
  given_by_.set( chr_givenby );
×
4910

4911
  item_given->setprop( "GivenBy", BLong::pack( chr_givenby->serial ) );
×
4912
  item_given->setprop( "GivenTo", BLong::pack( chr_givento->serial ) );
×
4913
  item_given->setprop( "GivenTime", BLong::pack( given_time_ ) );
×
4914
}
×
4915

4916
ItemGivenEvent::~ItemGivenEvent()
×
4917
{
4918
  /* See if the item is still in the container it was in
4919
       This means the AI script didn't do anything with it.
4920
       */
4921
  Items::Item* item = item_.get();
×
4922
  Core::UContainer* cont = cont_.get();
×
4923
  Mobile::Character* chr = given_by_.get();
×
4924

4925
  std::string given_time_str;
×
4926
  if ( !item->getprop( "GivenTime", given_time_str ) )
×
4927
    given_time_str = "";
×
4928

4929
  item->eraseprop( "GivenBy" );
×
4930
  item->eraseprop( "GivenTo" );
×
4931
  item->eraseprop( "GivenTime" );
×
4932

4933
  Bscript::BObject given_value( BObjectImp::unpack( given_time_str.c_str() ) );
×
4934
  int gts = given_value.impptr<BLong>()->value();
×
4935

4936
  if ( item->orphan() || cont->orphan() || chr->orphan() )
×
4937
    return;
×
4938

4939
  if ( item->container == cont && Clib::tostring( given_time_ ) == Clib::tostring( gts ) )
×
4940
  {
4941
    Core::UContainer* backpack = chr->backpack();
×
4942
    if ( backpack != nullptr && !chr->dead() )
×
4943
    {
4944
      if ( backpack->can_add( *item ) )
×
4945
      {
4946
        cont->remove( item );
×
4947
        u8 newSlot = 1;
×
4948
        if ( !backpack->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
×
4949
        {
4950
          item->setposition( chr->pos() );
×
4951
          add_item_to_world( item );
×
4952
          register_with_supporting_multi( item );
×
4953
          move_item( item, item->pos() );
×
4954
          return;
×
4955
        }
4956
        backpack->add( item, item->pos2d() );
×
4957
        update_item_to_inrange( item );
×
4958
        return;
×
4959
      }
4960
    }
4961
    cont->remove( item );
×
4962
    item->setposition( chr->pos() );
×
4963
    add_item_to_world( item );
×
4964
    register_with_supporting_multi( item );
×
4965
    move_item( item, item->pos() );
×
4966
  }
4967
}
×
4968

4969
GumpEvent::GumpEvent( Mobile::Character* source, Bscript::BObjectImp* resp )
6✔
4970
    : SourcedEvent( Core::EVID_GUMP_RESPONSE, source )
6✔
4971
{
4972
  addMember( "response", resp );
6✔
4973
}
6✔
4974
}  // namespace Module
4975

4976
namespace Network
4977
{
4978
using namespace Bscript;
4979
BObjectImp* Client::set_script_member_id( const int id, int value )
2✔
4980
{
4981
  switch ( id )
2✔
4982
  {
4983
  case MBR_DISABLE_INACTIVITY_TIMEOUT:
×
4984
    disable_inactivity_timeout( value );
×
4985
    return new BLong( disable_inactivity_timeout() );
×
4986
  case MBR_VISUAL_RANGE:
2✔
4987
    set_update_range_by_script( Clib::clamp_convert<u8>( value ) );
2✔
4988
    return new BLong( update_range() );
2✔
4989
  default:
×
4990
    return nullptr;
×
4991
  }
4992
}
4993

4994
BObjectImp* Client::get_script_member_id( const int id )
5✔
4995
{
4996
  switch ( id )
5✔
4997
  {
4998
  case MBR_ACCTNAME:
2✔
4999
    if ( acct != nullptr )
2✔
5000
      return new String( acct->name() );
2✔
5001
    return new BError( "Not attached to an account" );
×
5002
    break;
5003
  case MBR_ACCT:
2✔
5004
    if ( acct != nullptr )
2✔
5005
      return new Accounts::AccountObjImp( Accounts::AccountPtrHolder( Core::AccountRef( acct ) ) );
2✔
5006
    return new BError( "Not attached to an account" );
×
5007
    break;
5008
  case MBR_IP:
×
5009
    return new String( ipaddrAsString() );
×
5010
    break;
5011
  case MBR_CLIENTVERSION:
×
5012
    return new String( getversion() );
×
5013
    break;
5014
  case MBR_CLIENTVERSIONDETAIL:
×
5015
  {
5016
    std::unique_ptr<BStruct> info( new BStruct );
×
5017
    Network::VersionDetailStruct version = getversiondetail();
×
5018
    info->addMember( "major", new BLong( version.major ) );
×
5019
    info->addMember( "minor", new BLong( version.minor ) );
×
5020
    info->addMember( "rev", new BLong( version.rev ) );
×
5021
    info->addMember( "patch", new BLong( version.patch ) );
×
5022
    return info.release();
×
5023
  }
×
5024
  break;
5025
  case MBR_CLIENTINFO:
×
5026
    return getclientinfo();
×
5027
    break;
5028
  case MBR_CLIENTTYPE:
×
5029
    return new BLong( ClientType );
×
5030
    break;
5031
  case MBR_UO_EXPANSION_CLIENT:
×
5032
    return new BLong( UOExpansionFlagClient );
×
5033
    break;
5034
  case MBR_LAST_ACTIVITY_AT:
×
5035
    return new BLong( static_cast<s32>( last_activity_at() ) );
×
5036
    break;
5037
  case MBR_LAST_PACKET_AT:
×
5038
    return new BLong( static_cast<s32>( last_packet_at() ) );
×
5039
    break;
5040
  case MBR_PORT:
×
5041
    return new BLong( listen_port );
×
5042
    break;
5043
  case MBR_DISABLE_INACTIVITY_TIMEOUT:
×
5044
    return new BLong( disable_inactivity_timeout() );
×
5045
    break;
5046
  case MBR_VISUAL_RANGE:
×
5047
    return new BLong( update_range() );
×
5048
    break;
5049
  }
5050

5051
  return nullptr;
1✔
5052
}
5053

5054
}  // namespace Network
5055

5056
namespace Core
5057
{
5058
bool UObject::script_isa( unsigned isatype ) const
6,245✔
5059
{
5060
  return ( isatype == POLCLASS_OBJECT );
6,245✔
5061
}
5062

5063
bool ULockable::script_isa( unsigned isatype ) const
127✔
5064
{
5065
  return ( isatype == POLCLASS_LOCKABLE ) || base::script_isa( isatype );
127✔
5066
}
5067

5068
bool UContainer::script_isa( unsigned isatype ) const
174✔
5069
{
5070
  return ( isatype == POLCLASS_CONTAINER ) || base::script_isa( isatype );
174✔
5071
}
5072

5073
bool UCorpse::script_isa( unsigned isatype ) const
73✔
5074
{
5075
  return ( isatype == POLCLASS_CORPSE ) || base::script_isa( isatype );
73✔
5076
}
5077

5078
bool UDoor::script_isa( unsigned isatype ) const
1✔
5079
{
5080
  return ( isatype == POLCLASS_DOOR ) || base::script_isa( isatype );
1✔
5081
}
5082

5083
bool Spellbook::script_isa( unsigned isatype ) const
×
5084
{
5085
  return ( isatype == POLCLASS_SPELLBOOK ) || base::script_isa( isatype );
×
5086
}
5087

5088
bool Map::script_isa( unsigned isatype ) const
×
5089
{
5090
  return ( isatype == POLCLASS_MAP ) || base::script_isa( isatype );
×
5091
}
5092
}  // namespace Core
5093

5094
namespace Items
5095
{
5096
bool Item::script_isa( unsigned isatype ) const
6,232✔
5097
{
5098
  return ( isatype == Core::POLCLASS_ITEM ) || base::script_isa( isatype );
6,232✔
5099
}
5100

5101
bool Equipment::script_isa( unsigned isatype ) const
1✔
5102
{
5103
  return ( isatype == Core::POLCLASS_EQUIPMENT ) || base::script_isa( isatype );
1✔
5104
}
5105

5106
bool UArmor::script_isa( unsigned isatype ) const
1✔
5107
{
5108
  return ( isatype == Core::POLCLASS_ARMOR ) || base::script_isa( isatype );
1✔
5109
}
5110

5111
bool UWeapon::script_isa( unsigned isatype ) const
×
5112
{
5113
  return ( isatype == Core::POLCLASS_WEAPON ) || base::script_isa( isatype );
×
5114
}
5115
}  // namespace Items
5116

5117
namespace Mobile
5118
{
5119
bool Character::script_isa( unsigned isatype ) const
138✔
5120
{
5121
  return ( isatype == Core::POLCLASS_MOBILE ) || base::script_isa( isatype );
138✔
5122
}
5123

5124
bool NPC::script_isa( unsigned isatype ) const
56✔
5125
{
5126
  return ( isatype == Core::POLCLASS_NPC ) || base::script_isa( isatype );
56✔
5127
}
5128
}  // namespace Mobile
5129
namespace Multi
5130
{
5131
bool UMulti::script_isa( unsigned isatype ) const
3✔
5132
{
5133
  return ( isatype == Core::POLCLASS_MULTI ) || base::script_isa( isatype );
3✔
5134
}
5135

5136
bool UMulti::setgraphic( u16 /* newobjtype */ )
×
5137
{
5138
  return false;
×
5139
}
5140

5141
bool UBoat::script_isa( unsigned isatype ) const
9✔
5142
{
5143
  return ( isatype == Core::POLCLASS_BOAT ) || base::script_isa( isatype );
9✔
5144
}
5145

5146
bool UHouse::script_isa( unsigned isatype ) const
×
5147
{
5148
  return ( isatype == Core::POLCLASS_HOUSE ) || base::script_isa( isatype );
×
5149
}
5150
}  // namespace Multi
5151
}  // namespace Pol
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc