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

polserver / polserver / 25939934106

15 May 2026 08:30PM UTC coverage: 60.882% (-0.05%) from 60.929%
25939934106

push

github

turleypol
apply damage for items + evid_damaged

0 of 36 new or added lines in 2 files covered. (0.0%)

1083 existing lines in 14 files now uncovered.

44698 of 73417 relevant lines covered (60.88%)

524562.92 hits per line

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

56.62
/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/charactr.h"
87
#include "mobile/corpse.h"
88
#include "mobile/npc.h"
89
#include "mobile/ufacing.h"
90
#include "module/guildmod.h"
91
#include "module/partymod.h"
92
#include "module/uomod.h"
93
#include "multi/boat.h"
94
#include "multi/boatcomp.h"
95
#include "multi/house.h"
96
#include "multi/multi.h"
97
#include "network/cgdata.h"
98
#include "network/client.h"
99
#include "network/packethelper.h"
100
#include "network/packets.h"
101
#include "network/pktdef.h"
102
#include "npctmpl.h"
103
#include "polclass.h"
104
#include "polclock.h"
105
#include "proplist.h"
106
#include "realms/realm.h"
107
#include "realms/realms.h"
108
#include "spelbook.h"
109
#include "statmsg.h"
110
#include "syshookscript.h"
111
#include "tooltips.h"
112
#include "ufunc.h"
113
#include "umap.h"
114
#include "uobject.h"
115
#include "uoclient.h"
116
#include "uoexec.h"
117
#include "uworld.h"
118

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

641
namespace Core
642
{
643
using namespace Bscript;
644

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

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

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

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

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

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

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

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

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

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

792
namespace Items
793
{
794
using namespace Bscript;
795

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1630
    increv_send_object_recursive();
5✔
1631

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

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

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

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

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

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

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

1702

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

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

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

UNCOV
1719
    return new Module::EItemRefObjImp( new_stack );
×
1720

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1837
      UpdateCharacterWeight( existing_stack );
×
1838

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1967

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

1972

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

1976
    return baseValue;
36✔
1977
  };
1978

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3458

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3863
    increv_send_object_recursive();
13✔
3864

3865
    UpdateCharacterWeight( this );
13✔
3866

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4158
    Mobile::Character* chr;
4159

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4370

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

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

UNCOV
4382
  return imp;
×
4383
}
4384

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

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

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

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

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

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

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

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

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

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

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

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

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

4519

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4813

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5050
  return nullptr;
1✔
5051
}
5052

5053
}  // namespace Network
5054

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5145
bool UHouse::script_isa( unsigned isatype ) const
×
5146
{
UNCOV
5147
  return ( isatype == Core::POLCLASS_HOUSE ) || base::script_isa( isatype );
×
5148
}
5149
}  // namespace Multi
5150
}  // 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