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

polserver / polserver / 21066490217

16 Jan 2026 12:22PM UTC coverage: 60.507%. Remained the same
21066490217

push

github

web-flow
misc clang-tidy (#853)

* trigger tidy

* Automated clang-tidy change: modernize-use-equals-delete,modernize-make-shared,modernize-make-unique,modernize-use-constraints,readability-container-size-empty,modernize-redundant-void-arg,modernize-use-emplace

* removed non needed macros

* missed to disable tidy build

---------

Co-authored-by: Clang Tidy <clang-tidy@users.noreply.github.com>

174 of 248 new or added lines in 74 files covered. (70.16%)

2 existing lines in 2 files now uncovered.

44459 of 73477 relevant lines covered (60.51%)

515895.79 hits per line

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

55.79
/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 "exscrobj.h"
76
#include "fnsearch.h"
77
#include "globals/network.h"
78
#include "globals/uvars.h"
79
#include "item/armor.h"
80
#include "item/equipmnt.h"
81
#include "item/item.h"
82
#include "item/itemdesc.h"
83
#include "item/weapon.h"
84
#include "lockable.h"
85
#include "mobile/charactr.h"
86
#include "mobile/corpse.h"
87
#include "mobile/npc.h"
88
#include "mobile/ufacing.h"
89
#include "module/guildmod.h"
90
#include "module/partymod.h"
91
#include "module/uomod.h"
92
#include "multi/boat.h"
93
#include "multi/boatcomp.h"
94
#include "multi/house.h"
95
#include "multi/multi.h"
96
#include "network/cgdata.h"
97
#include "network/client.h"
98
#include "network/packethelper.h"
99
#include "network/packets.h"
100
#include "network/pktdef.h"
101
#include "npctmpl.h"
102
#include "polclass.h"
103
#include "polclock.h"
104
#include "proplist.h"
105
#include "realms/realm.h"
106
#include "realms/realms.h"
107
#include "spelbook.h"
108
#include "statmsg.h"
109
#include "syshookscript.h"
110
#include "tooltips.h"
111
#include "ufunc.h"
112
#include "umap.h"
113
#include "uobject.h"
114
#include "uoclient.h"
115
#include "uoexec.h"
116
#include "uworld.h"
117

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

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

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

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

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

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

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

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

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

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

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

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

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

236
      return ( chrref_imp->obj_->serial == obj_->serial );
32✔
237
    }
238
    else
239
      return false;
×
240
  }
241
  else 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
    else 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
85✔
277
{
278
  return new EOfflineCharacterRefObjImp( obj_.get() );
85✔
279
}
280

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

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

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

300
BObjectRef EItemRefObjImp::get_member_id( const int id )
525✔
301
{
302
  BObjectImp* result = obj_->get_script_member_id( id );
525✔
303
  if ( result != nullptr )
525✔
304
    return BObjectRef( result );
525✔
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
226✔
372
{
373
  return ( !obj_->orphan() );
226✔
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
  else 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
×
418
{
419
  return "BoatRef";
×
420
}
421
u8 EUBoatRefObjImp::typeOfInt() const
×
422
{
423
  return OTBoatRef;
×
424
}
425

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

431
BObjectRef EUBoatRefObjImp::get_member_id( const int id )
6,151✔
432
{
433
  BObjectImp* result = obj_->get_script_member_id( id );
6,151✔
434
  if ( result != nullptr )
6,151✔
435
    return BObjectRef( result );
6,151✔
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,
40✔
470
                                                bool forcebuiltin )
471
{
472
  if ( obj_->orphan() )
40✔
473
    return new BError( "That object no longer exists" );
×
474

475
  ObjMethod* mth = getObjMethod( id );
40✔
476
  if ( mth->overridden && !forcebuiltin )
40✔
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 );
40✔
483
  if ( imp != nullptr )
40✔
484
    return imp;
40✔
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
99✔
504
{
505
  return ( !obj_->orphan() );
99✔
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
  else 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
  else 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,701✔
646
{
647
  if ( orphan() )
7,701✔
648
    return new UninitObject;
14✔
649
  switch ( id )
7,687✔
650
  {
651
  case MBR_X:
182✔
652
    return new BLong( x() );
182✔
653
    break;
654
  case MBR_Y:
170✔
655
    return new BLong( y() );
170✔
656
    break;
657
  case MBR_Z:
151✔
658
    return new BLong( z() );
151✔
659
    break;
660
  case MBR_NAME:
43✔
661
    return new String( name() );
43✔
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:
523✔
670
    return new BLong( serial );
523✔
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
      else
694
        return new BLong( 0 );
4✔
695
    }
696
    else
697
      return new BLong( 0 );
×
698
    break;
699
  case MBR_REALM:
6,056✔
700
    if ( realm() != nullptr )
6,056✔
701
      return new String( realm()->name() );
6,056✔
702
    else
703
      return new BError( "object does not belong to a realm." );
×
704
    break;
705
  case MBR_SPECIFIC_NAME:
×
706
    return new BLong( specific_name() );
×
707
  default:
478✔
708
    return nullptr;
478✔
709
  }
710
}
711

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

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

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

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

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

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

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

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

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

793
namespace Items
794
{
795
using namespace Bscript;
796

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1629
    increv_send_object_recursive();
5✔
1630

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

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

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

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

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

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

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

1701

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

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

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

1718
    return new Module::EItemRefObjImp( new_stack );
×
1719

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1836
      UpdateCharacterWeight( existing_stack );
×
1837

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

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

1846
      return new Module::EItemRefObjImp( existing_stack );
×
1847
    }
1848
    else
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
    else if ( !ex.getItemParam( 0, cont ) )
×
1860
      return new BError( "No container specified" );
×
1861
    else if ( this->inuse() )
×
1862
      return new BError( "Item is in use" );
×
1863
    else 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 )
×
1871
      return new Module::EItemRefObjImp( existing_stack );
×
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 )
×
1885
    return this->script_method_id( objmethod->id, ex );
×
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

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

1909
BObject Item::call_custom_method( const char* methodname, BObjectImpRefVec& pmore )
×
1910
{
1911
  // no systemhook needed used for openbook uo module function
1912
  const ItemDesc& id = itemdesc();
×
1913
  if ( id.method_script != nullptr )
×
1914
  {
1915
    unsigned PC;
1916
    if ( id.method_script->FindExportedFunction(
×
1917
             methodname, static_cast<unsigned int>( pmore.size() + 1 ), PC ) )
×
1918
      return id.method_script->call( PC, new Module::EItemRefObjImp( this ), pmore );
×
1919
    else
1920
    {
1921
      std::string message;
×
1922
      message = "Method script for objtype " + id.objtype_description() +
×
1923
                " does not export function " + std::string( methodname ) + " taking " +
×
1924
                Clib::tostring( pmore.size() + 1 ) + " parameters";
×
1925
      BError* err = new BError( message );
×
1926
      return BObject( err );
×
1927
    }
×
1928
  }
1929
  return BObject( new BError( "No method script defined for " + id.objtype_description() ) );
×
1930
}
1931

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

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

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

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

1969

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

1974

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

1978
    return baseValue;
30✔
1979
  };
1980

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3271
    die();
72✔
3272
    return new BLong( 1 );
72✔
3273
    break;
3274
  case MTH_SETFACING:
×
3275
  {
3276
    int flags = 0;
×
3277
    Core::UFACING i_facing;
3278

3279
    if ( ex.hasParams( 2 ) && !ex.getParam( 1, flags, 0, 1 ) )
×
3280
      return new BError( "Invalid flags for parameter 1" );
×
3281

3282
    BObjectImp* param0 = ex.getParamImp( 0 );
×
3283
    if ( auto* s = impptrIf<String>( param0 ) )
×
3284
    {
3285
      if ( DecodeFacing( s->data(), i_facing ) == false )
×
3286
        return new BError( "Invalid string for parameter 0" );
×
3287
    }
3288
    else if ( auto* l = impptrIf<BLong>( param0 ) )
×
3289
    {
3290
      i_facing = static_cast<Core::UFACING>( l->value() & PKTIN_02_FACING_MASK );
×
3291
    }
3292
    else
3293
      return new BError( "Invalid type for parameter 0" );
×
3294

3295
    if ( !face( i_facing, flags ) )
×
3296
      return new BLong( 0 );
×
3297

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

3412
    if ( !ex.hasParams( 5 ) )
2✔
3413
      return new BError( "Not enough parameters" );
×
3414
    if ( ex.getParam( 0, icon ) && ex.getParam( 1, duration ) && ex.getParam( 2, cl_name ) &&
4✔
3415
         ex.getParam( 3, cl_descr ) && ex.getUnicodeStringParam( 4, desc_text ) )
4✔
3416
    {
3417
      if ( ex.hasParams( 6 ) )
2✔
3418
      {
3419
        const String* name_text;
3420
        if ( !ex.getUnicodeStringParam( 5, name_text ) )
×
3421
          break;
×
3422
        if ( name_text->length() > SPEECH_MAX_LEN )
×
3423
          return new BError( "Title text exceeds maximum size." );
×
3424
        name_args = name_text->value();
×
3425
      }
3426

3427
      if ( !( icon && cl_name && cl_descr ) )
2✔
3428
        return new BError( "Invalid parameters" );
×
3429

3430
      if ( desc_text->length() > SPEECH_MAX_LEN )
2✔
3431
        return new BError( "Text exceeds maximum size." );
×
3432

3433
      addBuff( icon, duration, cl_name, name_args, cl_descr, desc_text->value() );
2✔
3434
      return new BLong( 1 );
2✔
3435
    }
3436
    break;
×
3437
  }
2✔
3438
  case MTH_CLEAR_BUFFS:
2✔
3439
  {
3440
    clearBuffs();
2✔
3441

3442
    return new BLong( 1 );
2✔
3443
    break;
3444
  }
3445
  case MTH_DEL_BUFF:
2✔
3446
  {
3447
    u16 icon;
3448

3449
    if ( !ex.hasParams( 1 ) )
2✔
3450
      return new BError( "Not enough parameters" );
2✔
3451
    if ( ex.getParam( 0, icon ) )
2✔
3452
    {
3453
      if ( !icon )
2✔
3454
        return new BError( "Invalid parameter" );
×
3455

3456
      if ( !delBuff( icon ) )
2✔
3457
        return new BError( "Buff not found" );
1✔
3458

3459
      return new BLong( 1 );
1✔
3460
    }
3461
    break;
×
3462
  }
3463
  default:
11✔
3464
    return nullptr;
11✔
3465
  }
3466
  return new BError( "Invalid parameter type" );
×
3467
}
3468

3469

3470
BObjectImp* Character::script_method( const char* methodname, Core::UOExecutor& ex )
×
3471
{
3472
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
3473
  if ( objmethod != nullptr )
×
3474
    return this->script_method_id( objmethod->id, ex );
×
3475
  return nullptr;
×
3476
}
3477

3478
BObjectImp* Character::custom_script_method( const char* methodname, Core::UOExecutor& ex )
×
3479
{
3480
  // TODO uoclient entry deprecated
3481
  if ( Core::networkManager.uoclient_general.method_script != nullptr )
×
3482
  {
3483
    unsigned PC;
3484
    if ( Core::networkManager.uoclient_general.method_script->FindExportedFunction(
×
3485
             methodname, static_cast<unsigned int>( ex.numParams() + 1 ), PC ) )
×
3486
      return Core::networkManager.uoclient_general.method_script->call( PC, make_ref(),
×
3487
                                                                        ex.fparams );
×
3488
  }
3489
  return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
×
3490
}
3491

3492
ObjArray* Character::GetReportables() const
2✔
3493
{
3494
  std::unique_ptr<ObjArray> arr( new ObjArray );
2✔
3495

3496
  for ( ReportableList::const_iterator itr = reportable_.begin(), end = reportable_.end();
2✔
3497
        itr != end; ++itr )
4✔
3498
  {
3499
    const reportable_t& rt = ( *itr );
2✔
3500

3501
    std::unique_ptr<BObjectImp> kmember( nullptr );
2✔
3502
    Character* killer = Core::system_find_mobile( rt.serial );
2✔
3503
    if ( killer )
2✔
3504
      kmember = std::make_unique<Module::EOfflineCharacterRefObjImp>( killer );
2✔
3505
    else
NEW
3506
      kmember = std::make_unique<BError>( "Mobile not found" );
×
3507

3508
    std::unique_ptr<BStruct> elem( new BStruct );
2✔
3509
    elem->addMember( "serial", new BLong( rt.serial ) );
2✔
3510
    elem->addMember( "killer", kmember.release() );
2✔
3511
    elem->addMember( "gameclock", new BLong( static_cast<s32>( rt.polclock ) ) );
2✔
3512

3513
    arr->addElement( elem.release() );
2✔
3514
  }
2✔
3515
  return arr.release();
4✔
3516
}
2✔
3517

3518
ObjArray* Character::GetAggressorTo() const
×
3519
{
3520
  std::unique_ptr<ObjArray> arr( new ObjArray );
×
3521

3522
  for ( Character::MobileCont::const_iterator itr = aggressor_to_.begin(),
×
3523
                                              end = aggressor_to_.end();
×
3524
        itr != end; ++itr )
×
3525
  {
3526
    std::unique_ptr<BObjectImp> member( nullptr );
×
3527
    Character* chr = Core::system_find_mobile( ( *itr ).first->serial );
×
3528
    if ( chr )
×
NEW
3529
      member = std::make_unique<Module::EOfflineCharacterRefObjImp>( chr );
×
3530
    else
NEW
3531
      member = std::make_unique<BError>( "Mobile not found" );
×
3532

3533
    std::unique_ptr<BStruct> elem( new BStruct );
×
3534
    elem->addMember( "serial", new BLong( ( *itr ).first->serial ) );
×
3535
    elem->addMember( "ref", member.release() );
×
3536
    elem->addMember( "seconds",
×
3537
                     new BLong( static_cast<s32>( ( ( *itr ).second - Core::polclock() ) /
×
3538
                                                  Core::POLCLOCKS_PER_SEC ) ) );
×
3539

3540
    arr->addElement( elem.release() );
×
3541
  }
×
3542
  return arr.release();
×
3543
}
×
3544

3545
ObjArray* Character::GetLawFullyDamaged() const
×
3546
{
3547
  std::unique_ptr<ObjArray> arr( new ObjArray );
×
3548

3549
  for ( Character::MobileCont::const_iterator itr = lawfully_damaged_.begin(),
×
3550
                                              end = lawfully_damaged_.end();
×
3551
        itr != end; ++itr )
×
3552
  {
3553
    std::unique_ptr<BObjectImp> member( nullptr );
×
3554
    Character* chr = Core::system_find_mobile( ( *itr ).first->serial );
×
3555
    if ( chr )
×
NEW
3556
      member = std::make_unique<Module::EOfflineCharacterRefObjImp>( chr );
×
3557
    else
NEW
3558
      member = std::make_unique<BError>( "Mobile not found" );
×
3559

3560
    std::unique_ptr<BStruct> elem( new BStruct );
×
3561
    elem->addMember( "serial", new BLong( ( *itr ).first->serial ) );
×
3562
    elem->addMember( "ref", member.release() );
×
3563
    elem->addMember( "seconds",
×
3564
                     new BLong( static_cast<s32>( ( ( *itr ).second - Core::polclock() ) /
×
3565
                                                  Core::POLCLOCKS_PER_SEC ) ) );
×
3566

3567
    arr->addElement( elem.release() );
×
3568
  }
×
3569
  return arr.release();
×
3570
}
×
3571

3572
BObjectImp* NPC::get_script_member_id( const int id ) const
447✔
3573
{
3574
  BObjectImp* imp = base::get_script_member_id( id );
447✔
3575
  if ( imp != nullptr )
447✔
3576
    return imp;
387✔
3577

3578
  switch ( id )
60✔
3579
  {
3580
  case MBR_SCRIPT:
1✔
3581
    return new String( script );
1✔
3582
    break;
3583
  case MBR_NPCTEMPLATE:
×
3584
    return new String( template_name );
×
3585
    break;
3586
  case MBR_MASTER:
1✔
3587
  {
3588
    Character* master = master_.get();
1✔
3589
    if ( master != nullptr && !master->orphan() )
1✔
3590
      return new Module::EOfflineCharacterRefObjImp( master );
1✔
3591
    return new BLong( 0 );
×
3592
    break;
3593
  }
3594

3595
  case MBR_PROCESS:
52✔
3596
    if ( ex )
52✔
3597
      return new Core::ScriptExObjImp( ex );
52✔
3598
    return new BError( "No script running" );
×
3599
    break;
3600

3601
  case MBR_EVENTMASK:
×
3602
    if ( ex )
×
3603
      return new BLong( ex->eventmask );
×
3604
    return new BError( "No script running" );
×
3605
    break;
3606

3607
  case MBR_SPEECH_COLOR:
1✔
3608
    return new BLong( speech_color() );
1✔
3609
    break;
3610
  case MBR_SPEECH_FONT:
1✔
3611
    return new BLong( speech_font() );
1✔
3612
    break;
3613
  case MBR_USE_ADJUSTMENTS:
1✔
3614
    return new BLong( use_adjustments() ? 1 : 0 );
1✔
3615
    break;
3616
  case MBR_RUN_SPEED:
1✔
3617
    return new BLong( run_speed );
1✔
3618
    break;
3619
  case MBR_ALIGNMENT:
×
3620
    return new BLong( template_->alignment );
×
3621
    break;
3622
  case MBR_SAVEONEXIT:
×
3623
    return new BLong( saveonexit() );
×
3624
    break;
3625
  case MBR_NO_DROP_EXCEPTION:
2✔
3626
    return new BLong( no_drop_exception() );
2✔
3627
  default:
×
3628
    return nullptr;
×
3629
  }
3630
}
3631

3632
BObjectImp* NPC::get_script_member( const char* membername ) const
35✔
3633
{
3634
  ObjMember* objmember = getKnownObjMember( membername );
35✔
3635
  if ( objmember != nullptr )
35✔
3636
    return this->get_script_member_id( objmember->id );
35✔
3637
  return nullptr;
×
3638
}
3639

3640
BObjectImp* NPC::set_script_member_id( const int id, const std::string& value )
×
3641
{
3642
  BObjectImp* imp = base::set_script_member_id( id, value );
×
3643
  if ( imp != nullptr )
×
3644
    return imp;
×
3645
  switch ( id )
×
3646
  {
3647
  case MBR_SCRIPT:
×
3648
    return new String( script = value );
×
3649
  default:
×
3650
    return nullptr;
×
3651
  }
3652
}
3653

3654
BObjectImp* NPC::set_script_member( const char* membername, const std::string& value )
×
3655
{
3656
  ObjMember* objmember = getKnownObjMember( membername );
×
3657
  if ( objmember != nullptr )
×
3658
    return this->set_script_member_id( objmember->id, value );
×
3659
  return nullptr;
×
3660
}
3661

3662
BObjectImp* NPC::set_script_member_id( const int id, int value )
29✔
3663
{
3664
  BObjectImp* imp = base::set_script_member_id( id, value );
29✔
3665
  if ( imp != nullptr )
29✔
3666
    return imp;
22✔
3667
  switch ( id )
7✔
3668
  {
3669
  case MBR_SPEECH_COLOR:
×
3670
    speech_color( Clib::clamp_convert<u16>( value ) );
×
3671
    return new BLong( speech_color() );
×
3672
  case MBR_SPEECH_FONT:
×
3673
    speech_font( Clib::clamp_convert<u16>( value ) );
×
3674
    return new BLong( speech_font() );
×
3675
  case MBR_USE_ADJUSTMENTS:
×
3676
    use_adjustments( value ? true : false );
×
3677
    return new BLong( use_adjustments() );
×
3678
  case MBR_RUN_SPEED:
×
3679
    return new BLong( run_speed = Clib::clamp_convert<u16>( value ) );
×
3680
  case MBR_SAVEONEXIT:
1✔
3681
    saveonexit( value ? true : false );
1✔
3682
    return new BLong( saveonexit() );
1✔
3683
  case MBR_NO_DROP_EXCEPTION:
×
3684
    no_drop_exception( value ? true : false );
×
3685
    return new BLong( no_drop_exception() );
×
3686
  default:
6✔
3687
    return nullptr;
6✔
3688
  }
3689
}
3690
BObjectImp* NPC::set_script_member( const char* membername, int value )
×
3691
{
3692
  ObjMember* objmember = getKnownObjMember( membername );
×
3693
  if ( objmember != nullptr )
×
3694
    return this->set_script_member_id( objmember->id, value );
×
3695
  return nullptr;
×
3696
}
3697

3698
BObjectImp* NPC::script_method_id( const int id, Core::UOExecutor& executor )
157✔
3699
{
3700
  BObjectImp* imp = base::script_method_id( id, executor );
157✔
3701
  if ( imp != nullptr )
157✔
3702
    return imp;
146✔
3703

3704
  switch ( id )
11✔
3705
  {
3706
  case MTH_SETMASTER:
11✔
3707
  {
3708
    if ( executor.numParams() != 1 )
11✔
3709
      return new BError( "Not enough parameters" );
×
3710
    Character* chr;
3711
    set_dirty();
11✔
3712
    if ( executor.getCharacterParam( 0, chr ) )
11✔
3713
    {
3714
      master_.set( chr );
11✔
3715
      return new BLong( 1 );
11✔
3716
    }
3717
    else
3718
    {
3719
      master_.clear();
×
3720
      return new BLong( 0 );
×
3721
    }
3722
    break;
3723
  }
3724
  default:
×
3725
    return nullptr;
×
3726
  }
3727
}
3728

3729
BObjectImp* NPC::script_method( const char* methodname, Core::UOExecutor& executor )
×
3730
{
3731
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
3732
  if ( objmethod != nullptr )
×
3733
    return this->script_method_id( objmethod->id, executor );
×
3734
  return nullptr;
×
3735
}
3736

3737
BObjectImp* NPC::custom_script_method( const char* methodname, Core::UOExecutor& executor )
×
3738
{
3739
  if ( template_->method_script != nullptr )
×
3740
  {
3741
    unsigned PC;
3742
    if ( template_->method_script->FindExportedFunction(
×
3743
             methodname, static_cast<unsigned int>( executor.numParams() + 1 ), PC ) )
×
3744
      return template_->method_script->call( PC, make_ref(), executor.fparams );
×
3745
  }
3746
  return Core::gamestate.system_hooks.call_script_method( methodname, &executor, this );
×
3747
}
3748
}  // namespace Mobile
3749
namespace Core
3750
{
3751
using namespace Bscript;
3752

3753
BObjectImp* ULockable::get_script_member_id( const int id ) const
238✔
3754
{
3755
  BObjectImp* imp = Item::get_script_member_id( id );
238✔
3756
  if ( imp != nullptr )
238✔
3757
    return imp;
192✔
3758

3759
  switch ( id )
46✔
3760
  {
3761
  case MBR_LOCKED:
1✔
3762
    return new BLong( locked() ? 1 : 0 );
1✔
3763
    break;
3764
  default:
45✔
3765
    return nullptr;
45✔
3766
  }
3767
}
3768

3769
BObjectImp* ULockable::get_script_member( const char* membername ) const
×
3770
{
3771
  ObjMember* objmember = getKnownObjMember( membername );
×
3772
  if ( objmember != nullptr )
×
3773
    return this->get_script_member_id( objmember->id );
×
3774
  return nullptr;
×
3775
}
3776

3777
BObjectImp* ULockable::set_script_member_id( const int id, int value )
61✔
3778
{
3779
  BObjectImp* imp = Item::set_script_member_id( id, value );
61✔
3780
  if ( imp != nullptr )
61✔
3781
    return imp;
48✔
3782
  switch ( id )
13✔
3783
  {
3784
  case MBR_LOCKED:
1✔
3785
    locked( value ? true : false );
1✔
3786
    return new BLong( locked() );
1✔
3787
  default:
12✔
3788
    return nullptr;
12✔
3789
  }
3790
}
3791

3792
BObjectImp* ULockable::set_script_member( const char* membername, int value )
×
3793
{
3794
  ObjMember* objmember = getKnownObjMember( membername );
×
3795
  if ( objmember != nullptr )
×
3796
    return this->set_script_member_id( objmember->id, value );
×
3797
  return nullptr;
×
3798
}
3799

3800
BObjectImp* UContainer::get_script_member_id( const int id ) const
218✔
3801
{
3802
  BObjectImp* imp = base::get_script_member_id( id );
218✔
3803
  if ( imp != nullptr )
218✔
3804
    return imp;
173✔
3805

3806
  switch ( id )
45✔
3807
  {
3808
  case MBR_MAX_ITEMS_MOD:
1✔
3809
    return new BLong( max_items_mod() );
1✔
3810
    break;
3811
  case MBR_MAX_WEIGHT_MOD:
1✔
3812
    return new BLong( max_weight_mod() );
1✔
3813
    break;
3814
  case MBR_MAX_SLOTS_MOD:
1✔
3815
    return new BLong( max_slots_mod() );
1✔
3816
    break;
3817
  case MBR_NO_DROP_EXCEPTION:
2✔
3818
    return new BLong( no_drop_exception() );
2✔
3819
  case MBR_HELD_WEIGHT_MULTIPLIER:
8✔
3820
    return new Double( held_weight_multiplier() );
8✔
3821
  default:
32✔
3822
    return nullptr;
32✔
3823
  }
3824
}
3825

3826
BObjectImp* UContainer::get_script_member( const char* membername ) const
6✔
3827
{
3828
  ObjMember* objmember = getKnownObjMember( membername );
6✔
3829
  if ( objmember != nullptr )
6✔
3830
    return this->get_script_member_id( objmember->id );
6✔
3831
  return nullptr;
×
3832
}
3833

3834
BObjectImp* UContainer::set_script_member_id( const int id, int value )
61✔
3835
{
3836
  BObjectImp* imp = base::set_script_member_id( id, value );
61✔
3837
  if ( imp != nullptr )
61✔
3838
    return imp;
49✔
3839
  switch ( id )
12✔
3840
  {
3841
  case MBR_MAX_ITEMS_MOD:
1✔
3842
    max_items_mod( Clib::clamp_convert<s16>( value ) );
1✔
3843
    break;
1✔
3844
  case MBR_MAX_WEIGHT_MOD:
1✔
3845
    max_weight_mod( Clib::clamp_convert<s16>( value ) );
1✔
3846
    break;
1✔
3847
  case MBR_MAX_SLOTS_MOD:
1✔
3848
    max_slots_mod( Clib::clamp_convert<s8>( value ) );
1✔
3849
    break;
1✔
3850
  case MBR_NO_DROP_EXCEPTION:
2✔
3851
    no_drop_exception( value ? true : false );
2✔
3852
    return new BLong( no_drop_exception() );
2✔
3853
  case MBR_WEIGHT_MULTIPLIER_MOD:
×
3854
    return set_script_member_id_double( id, value );
×
3855
  case MBR_HELD_WEIGHT_MULTIPLIER:
7✔
3856
    return set_script_member_id_double( id, value );
7✔
3857
  default:
×
3858
    return nullptr;
×
3859
  }
3860
  return new BLong( value );
3✔
3861
}
3862

3863
Bscript::BObjectImp* UContainer::set_script_member_id_double( const int id, double value )
13✔
3864
{
3865
  BObjectImp* imp = base::set_script_member_id_double( id, value );
13✔
3866
  if ( imp != nullptr )
13✔
3867
    return imp;
×
3868

3869
  switch ( id )
13✔
3870
  {
3871
  case MBR_HELD_WEIGHT_MULTIPLIER:
13✔
3872
  {
3873
    if ( container )
13✔
3874
    {
3875
      int oldweight = weight();
8✔
3876
      held_weight_multiplier( value );
8✔
3877
      container->add_bulk( 0, weight() - oldweight );
8✔
3878
    }
3879
    else
3880
    {
3881
      held_weight_multiplier( value );
5✔
3882
    }
3883

3884
    increv_send_object_recursive();
13✔
3885

3886
    UpdateCharacterWeight( this );
13✔
3887

3888
    return new Double( held_weight_multiplier() );
13✔
3889
  }
3890
  default:
×
3891
    break;
×
3892
  }
3893
  return nullptr;
×
3894
}
3895

3896
BObjectImp* UContainer::set_script_member( const char* membername, int value )
53✔
3897
{
3898
  ObjMember* objmember = getKnownObjMember( membername );
53✔
3899
  if ( objmember != nullptr )
53✔
3900
    return this->set_script_member_id( objmember->id, value );
53✔
3901
  return nullptr;
×
3902
}
3903

3904
BObjectImp* UCorpse::get_script_member_id( const int id ) const
39✔
3905
{
3906
  BObjectImp* imp = base::get_script_member_id( id );
39✔
3907
  if ( imp != nullptr )
39✔
3908
    return imp;
7✔
3909

3910
  switch ( id )
32✔
3911
  {
3912
  case MBR_CORPSETYPE:
1✔
3913
    return new BLong( corpsetype );
1✔
3914
    break;
3915
  case MBR_OWNERSERIAL:
31✔
3916
    return new BLong( ownerserial );
31✔
3917
    break;
3918
  default:
×
3919
    return nullptr;
×
3920
  }
3921
}
3922

3923
BObjectImp* UCorpse::get_script_member( const char* membername ) const
2✔
3924
{
3925
  ObjMember* objmember = getKnownObjMember( membername );
2✔
3926
  if ( objmember != nullptr )
2✔
3927
    return this->get_script_member_id( objmember->id );
2✔
3928
  return nullptr;
×
3929
}
3930

3931
BObjectImp* Spellbook::script_method_id( const int id, Core::UOExecutor& ex )
4✔
3932
{
3933
  BObjectImp* imp = base::script_method_id( id, ex );
4✔
3934
  if ( imp != nullptr )
4✔
3935
    return imp;
×
3936

3937
  switch ( id )
4✔
3938
  {
3939
  case MTH_HASSPELL:
2✔
3940
  {
3941
    u32 sid;
3942
    if ( !ex.hasParams( 1 ) )
2✔
3943
      return new BError( "Not enough parameters" );
2✔
3944
    if ( ex.getParam( 0, sid ) )
2✔
3945
    {
3946
      if ( sid == 0 )
2✔
3947
        return new BError( "SpellID must be >= 1" );
×
3948
      if ( this->has_spellid( sid ) )
2✔
3949
        return new BLong( 1 );
2✔
3950
      else
3951
        return new BLong( 0 );
×
3952
    }
3953
    break;
×
3954
  }
3955
  case MTH_SPELLS:
×
3956
  {
3957
    std::unique_ptr<ObjArray> arr( new ObjArray );
×
3958
    for ( u16 i = 0; i < 64; ++i )
×
3959
    {
3960
      unsigned int sid;
3961

3962
      // Check for Mysticism spells here
3963
      if ( this->spell_school == 3 )
×
3964
        sid = 678 + i;
×
3965
      else
3966
        sid = this->spell_school * 100 + i + 1;
×
3967

3968
      if ( this->has_spellid( sid ) )
×
3969
        arr->addElement( new BLong( sid ) );
×
3970
    }
3971
    return arr.release();
×
3972
    break;
3973
  }
×
3974
  case MTH_REMOVESPELL:
×
3975
  {
3976
    u32 sid;
3977
    if ( !ex.hasParams( 1 ) )
×
3978
      return new BError( "Not enough parameters" );
×
3979
    if ( ex.getParam( 0, sid ) )
×
3980
    {
3981
      if ( sid == 0 )
×
3982
        return new BError( "SpellID must be >= 1" );
×
3983
      if ( this->remove_spellid( sid ) )
×
3984
        return new BLong( 1 );
×
3985
      else
3986
        return new BLong( 0 );
×
3987
    }
3988
    break;
×
3989
  }
3990
  case MTH_ADDSPELL:
2✔
3991
  {
3992
    u32 sid;
3993
    if ( !ex.hasParams( 1 ) )
2✔
3994
      return new BError( "Not enough parameters" );
2✔
3995
    if ( ex.getParam( 0, sid ) )
2✔
3996
    {
3997
      if ( sid == 0 )
2✔
3998
        return new BError( "SpellID must be >= 1" );
×
3999
      if ( this->add_spellid( sid ) )
2✔
4000
        return new BLong( 1 );
2✔
4001
      else
4002
        return new BLong( 0 );
×
4003
    }
4004
    break;
×
4005
  }
4006

4007
  default:
×
4008
    return nullptr;
×
4009
  }
4010
  return new BError( "Invalid parameter type" );
×
4011
}
4012

4013
BObjectImp* Spellbook::script_method( const char* methodname, Core::UOExecutor& ex )
×
4014
{
4015
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4016
  if ( objmethod != nullptr )
×
4017
    return this->script_method_id( objmethod->id, ex );
×
4018
  return nullptr;
×
4019
}
4020
}  // namespace Core
4021
namespace Multi
4022
{
4023
using namespace Bscript;
4024

4025
BObjectImp* UBoat::make_ref()
5✔
4026
{
4027
  return new Module::EUBoatRefObjImp( this );
5✔
4028
}
4029

4030
BObjectImp* UMulti::make_ref()
23✔
4031
{
4032
  return new Module::EMultiRefObjImp( this );
23✔
4033
}
4034

4035
BObjectImp* UBoat::get_script_member_id( const int id ) const
6,153✔
4036
{
4037
  BObjectImp* imp = base::get_script_member_id( id );
6,153✔
4038
  if ( imp != nullptr )
6,153✔
4039
    return imp;
6,116✔
4040

4041
  switch ( id )
37✔
4042
  {
4043
  case MBR_TILLERMAN:
×
4044
  {
4045
    Item* cp = tillerman;
×
4046
    if ( cp != nullptr )
×
4047
      return new Module::EItemRefObjImp( cp );
×
4048
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4049
    break;
4050
  }
4051
  case MBR_PORTPLANK:
20✔
4052
  {
4053
    Item* cp = portplank;
20✔
4054
    if ( cp != nullptr )
20✔
4055
      return new Module::EItemRefObjImp( cp );
20✔
4056
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4057
    break;
4058
  }
4059
  case MBR_STARBOARDPLANK:
×
4060
  {
4061
    Item* cp = starboardplank;
×
4062
    if ( cp != nullptr )
×
4063
      return new Module::EItemRefObjImp( cp );
×
4064
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4065
    break;
4066
  }
4067
  case MBR_HOLD:
×
4068
  {
4069
    Item* cp = hold;
×
4070
    if ( cp != nullptr )
×
4071
      return new Module::EItemRefObjImp( cp );
×
4072
    return new BError( std::string( "This ship doesn't have that component" ) );
×
4073
    break;
4074
  }
4075
  case MBR_ROPE:
×
4076
    return component_list( COMPONENT_ROPE );
×
4077
    break;
4078
  case MBR_WHEEL:
×
4079
    return component_list( COMPONENT_WHEEL );
×
4080
    break;
4081
  case MBR_HULL:
×
4082
    return component_list( COMPONENT_HULL );
×
4083
    break;
4084
  case MBR_TILLER:
×
4085
    return component_list( COMPONENT_TILLER );
×
4086
    break;
4087
  case MBR_RUDDER:
×
4088
    return component_list( COMPONENT_RUDDER );
×
4089
    break;
4090
  case MBR_SAILS:
×
4091
    return component_list( COMPONENT_SAILS );
×
4092
    break;
4093
  case MBR_STORAGE:
×
4094
    return component_list( COMPONENT_STORAGE );
×
4095
    break;
4096
  case MBR_WEAPONSLOT:
×
4097
    return component_list( COMPONENT_WEAPONSLOT );
×
4098
    break;
4099
  case MBR_COMPONENTS:
1✔
4100
    return component_list( COMPONENT_ALL );
1✔
4101
    break;
4102
  case MBR_ITEMS:
3✔
4103
    return items_list();
3✔
4104
    break;
4105
  case MBR_MOBILES:
4✔
4106
    return mobiles_list();
4✔
4107
    break;
4108
  case MBR_HAS_OFFLINE_MOBILES:
×
4109
    return new BLong( has_offline_mobiles() ? 1 : 0 );
×
4110
    break;
4111
  case MBR_MULTIID:
6✔
4112
    return new BLong( multiid_ );
6✔
4113
    break;
4114
  case MBR_PILOT:
3✔
4115
  {
4116
    Mobile::Character* owner = pilot();
3✔
4117
    if ( owner != nullptr )
3✔
4118
    {
4119
      return new Module::ECharacterRefObjImp( owner );
2✔
4120
    }
4121
  }
4122
    return new BLong( 0 );
1✔
4123
  default:
×
4124
    return nullptr;
×
4125
  }
4126
}
4127

4128
BObjectImp* UBoat::get_script_member( const char* membername ) const
2✔
4129
{
4130
  ObjMember* objmember = getKnownObjMember( membername );
2✔
4131
  if ( objmember != nullptr )
2✔
4132
    return this->get_script_member_id( objmember->id );
2✔
4133
  return nullptr;
×
4134
}
4135

4136
BObjectImp* UBoat::script_method_id( const int id, Core::UOExecutor& ex )
40✔
4137
{
4138
  BObjectImp* imp = base::script_method_id( id, ex );
40✔
4139
  if ( imp != nullptr )
40✔
4140
    return imp;
26✔
4141

4142
  switch ( id )
14✔
4143
  {
4144
  case MTH_MOVE_OFFLINE_MOBILES:
×
4145
  {
4146
    if ( ex.numParams() == 3 )
×
4147
    {
4148
      Core::Pos3d pos;
×
4149
      if ( !ex.getPos3dParam( 0, 1, 2, &pos, realm() ) )
×
4150
        return new BError( "Invalid parameter type" );
×
4151
      set_dirty();
×
4152
      move_offline_mobiles( Core::Pos4d( pos, realm() ) );
×
4153
      return new BLong( 1 );
×
4154
    }
4155
    else if ( ex.numParams() == 4 )
×
4156
    {
4157
      Core::Pos4d pos;
×
4158
      if ( !ex.getPos4dParam( 0, 1, 2, 3, &pos ) )
×
4159
        return new BError( "Invalid parameter type" );
×
4160
      set_dirty();
×
4161
      move_offline_mobiles( pos );
×
4162
      return new BLong( 1 );
×
4163
    }
4164
    return new BError( "Not enough parameters" );
×
4165
  }
4166
  case MTH_SET_PILOT:
10✔
4167
  {
4168
    if ( !ex.hasParams( 1 ) )
10✔
4169
    {
4170
      return new BError( "Not enough parameters" );
×
4171
    }
4172

4173
    BObjectImp* impMaybeZero = ex.getParamImp( 0 );
10✔
4174

4175
    if ( auto* value = impptrIf<BLong>( impMaybeZero ) )
10✔
4176
    {
4177
      if ( value->value() != 0 )
6✔
4178
        return new BError( "Invalid parameters" );
×
4179
      return set_pilot( nullptr );
6✔
4180
    }
4181
    else
4182
    {
4183
      Mobile::Character* chr;
4184

4185
      if ( !ex.getCharacterParam( 0, chr ) )
4✔
4186
        return new BError( "Invalid parameters" );
×
4187

4188
      return set_pilot( chr );
4✔
4189
    }
4190
  }
4191
  case MTH_SET_ALTERNATE_MULTIID:
4✔
4192
  {
4193
    if ( ex.numParams() != 1 )
4✔
4194
      return new BError( "Not enough parameters" );
×
4195
    u32 index;
4196
    if ( !ex.getParam( 0, index ) )
4✔
4197
      return new BError( "Invalid parameter type" );
×
4198
    const auto& desc = static_cast<const Items::BoatDesc&>( itemdesc() );
4✔
4199
    if ( index >= desc.alternates.size() )
4✔
4200
      return new BError( "Index out of range" );
1✔
4201

4202
    {
4203
      UBoat::BoatMoveGuard guard( this );
3✔
4204
      u16 new_multiid = desc.alternates[index];
3✔
4205
      u16 base_multi = multiid_ & ~3u;
3✔
4206
      u16 multioffset = multiid_ - base_multi;
3✔
4207
      multiid_ = new_multiid + multioffset;
3✔
4208
    }
3✔
4209
    transform_components( boatshape() );
3✔
4210
    send_display_boat_to_inrange( {} );
3✔
4211
    return new BLong( 1 );
3✔
4212
  }
4213
  default:
×
4214
    return nullptr;
×
4215
  }
4216
}
4217

4218
BObjectImp* UBoat::script_method( const char* methodname, Core::UOExecutor& ex )
×
4219
{
4220
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4221
  if ( objmethod != nullptr )
×
4222
    return this->script_method_id( objmethod->id, ex );
×
4223
  return nullptr;
×
4224
}
4225

4226
BObjectImp* UPlank::get_script_member_id( const int id ) const
20✔
4227
{
4228
  switch ( id )
20✔
4229
  {
4230
  case MBR_MULTI:
×
4231
    if ( boat_.get() )
×
4232
      return new Module::EUBoatRefObjImp( boat_.get() );
×
4233
    return new BError( "No boat attached" );
×
4234
    break;
4235
  }
4236
  return base::get_script_member_id( id );
20✔
4237
}
4238

4239
/* UObject defines a 'multi' also, so we have to trap that here first */
4240
BObjectImp* UPlank::get_script_member( const char* membername ) const
×
4241
{
4242
  ObjMember* objmember = getKnownObjMember( membername );
×
4243
  if ( objmember != nullptr )
×
4244
    return this->get_script_member_id( objmember->id );
×
4245
  return base::get_script_member( membername );
×
4246
}
4247
}  // namespace Multi
4248
namespace Core
4249
{
4250
using namespace Bscript;
4251

4252
BObjectImp* Map::get_script_member_id( const int id ) const
9✔
4253
{
4254
  BObjectImp* imp = base::get_script_member_id( id );
9✔
4255
  if ( imp != nullptr )
9✔
4256
    return imp;
1✔
4257

4258
  switch ( id )
8✔
4259
  {
4260
  case MBR_XEAST:
1✔
4261
    return new BLong( xeast );
1✔
4262
  case MBR_XWEST:
1✔
4263
    return new BLong( xwest );
1✔
4264
  case MBR_YNORTH:
1✔
4265
    return new BLong( ynorth );
1✔
4266
  case MBR_YSOUTH:
1✔
4267
    return new BLong( ysouth );
1✔
4268
  case MBR_GUMPWIDTH:
1✔
4269
    return new BLong( gumpsize.x() );
1✔
4270
  case MBR_GUMPHEIGHT:
1✔
4271
    return new BLong( gumpsize.y() );
1✔
4272
  case MBR_FACETID:
1✔
4273
    return new BLong( facetid );
1✔
4274
  case MBR_EDITABLE:
1✔
4275
    return new BLong( editable ? 1 : 0 );
1✔
4276
  default:
×
4277
    return nullptr;
×
4278
  }
4279
}
4280

4281
BObjectImp* Map::get_script_member( const char* membername ) const
8✔
4282
{
4283
  ObjMember* objmember = getKnownObjMember( membername );
8✔
4284
  if ( objmember != nullptr )
8✔
4285
    return this->get_script_member_id( objmember->id );
8✔
4286
  return nullptr;
×
4287
}
4288

4289
BObjectImp* Map::set_script_member_id( const int id, int value )
8✔
4290
{
4291
  BObjectImp* imp = base::set_script_member_id( id, value );
8✔
4292
  if ( imp != nullptr )
8✔
4293
    return imp;
×
4294
  switch ( id )
8✔
4295
  {
4296
  case MBR_XEAST:
1✔
4297
    return new BLong( xeast = Clib::clamp_convert<u16>( value ) );
1✔
4298
  case MBR_XWEST:
1✔
4299
    return new BLong( xwest = Clib::clamp_convert<u16>( value ) );
1✔
4300
  case MBR_YNORTH:
1✔
4301
    return new BLong( ynorth = Clib::clamp_convert<u16>( value ) );
1✔
4302
  case MBR_YSOUTH:
1✔
4303
    return new BLong( ysouth = Clib::clamp_convert<u16>( value ) );
1✔
4304
  case MBR_GUMPWIDTH:
1✔
4305
    gumpsize.x( Clib::clamp_convert<u16>( value ) );
1✔
4306
    return new BLong( gumpsize.x() );
1✔
4307
  case MBR_GUMPHEIGHT:
1✔
4308
    gumpsize.y( Clib::clamp_convert<u16>( value ) );
1✔
4309
    return new BLong( gumpsize.y() );
1✔
4310
  case MBR_FACETID:
1✔
4311
    return new BLong( facetid = Clib::clamp_convert<u16>( value ) );
1✔
4312
  case MBR_EDITABLE:
1✔
4313
    return new BLong( editable = value ? true : false );
1✔
4314
  default:
×
4315
    return nullptr;
×
4316
  }
4317
}
4318
BObjectImp* Map::set_script_member( const char* membername, int value )
8✔
4319
{
4320
  ObjMember* objmember = getKnownObjMember( membername );
8✔
4321
  if ( objmember != nullptr )
8✔
4322
    return this->set_script_member_id( objmember->id, value );
8✔
4323
  return nullptr;
×
4324
}
4325

4326
BObjectImp* UObject::script_method_id( const int id, Core::UOExecutor& ex )
644✔
4327
{
4328
  switch ( id )
644✔
4329
  {
4330
  case MTH_ISA:
×
4331
  {
4332
    if ( !ex.hasParams( 1 ) )
×
4333
      return new BError( "Not enough parameters" );
×
4334
    u32 isatype;
4335
    if ( ex.getParam( 0, isatype ) )
×
4336
      return new BLong( script_isa( isatype ) );
×
4337
    break;
×
4338
  }
4339
  case MTH_SET_MEMBER:
189✔
4340
  {
4341
    if ( !ex.hasParams( 2 ) )
189✔
4342
      return new BError( "Not enough parameters" );
189✔
4343
    BObjectImp* objimp;
4344
    const String* mname;
4345
    if ( ex.getStringParam( 0, mname ) && ( objimp = ex.getParamImp( 1 ) ) != nullptr )
189✔
4346
    {
4347
      BObjectImp* ret;
4348
      if ( auto* l = impptrIf<BLong>( objimp ) )
189✔
4349
        ret = set_script_member( mname->value().c_str(), l->value() );
170✔
4350
      else if ( auto* d = impptrIf<Double>( objimp ) )
19✔
4351
        ret = set_script_member_double( mname->value().c_str(), d->value() );
6✔
4352
      else if ( auto* s = impptrIf<String>( objimp ) )
13✔
4353
        ret = set_script_member( mname->value().c_str(), s->value() );
13✔
4354
      else
4355
        return new BError( "Invalid value type" );
×
4356

4357
      if ( ret != nullptr )
189✔
4358
        return ret;
189✔
4359
      else
4360
      {
4361
        std::string message = std::string( "Member " ) + std::string( mname->value() ) +
×
4362
                              std::string( " not found on that object" );
×
4363
        return new BError( message );
×
4364
      }
×
4365
    }
4366
    break;
×
4367
  }
4368
  case MTH_GET_MEMBER:
246✔
4369
  {
4370
    if ( !ex.hasParams( 1 ) )
246✔
4371
      return new BError( "Not enough parameters" );
246✔
4372

4373
    const String* mname;
4374
    if ( ex.getStringParam( 0, mname ) )
246✔
4375
    {
4376
      BObjectImp* ret = get_script_member( mname->value().c_str() );
246✔
4377
      if ( ret != nullptr )
246✔
4378
        return ret;
246✔
4379
      else
4380
      {
4381
        std::string message = std::string( "Member " ) + std::string( mname->value() ) +
×
4382
                              std::string( " not found on that object" );
×
4383
        return new BError( message );
×
4384
      }
×
4385
    }
4386
    break;
×
4387
  }
4388
  default:
209✔
4389
  {
4390
    bool changed = false;
209✔
4391
    BObjectImp* imp = CallPropertyListMethod_id( proplist_, id, ex, changed );
209✔
4392
    if ( changed )
209✔
4393
      set_dirty();
43✔
4394
    return imp;
209✔
4395
  }
4396
  }
4397
  return new BError( "Invalid parameter type" );
×
4398
}
4399

4400

4401
BObjectImp* UObject::script_method( const char* methodname, Core::UOExecutor& ex )
×
4402
{
4403
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4404
  if ( objmethod != nullptr )
×
4405
    return this->script_method_id( objmethod->id, ex );
×
4406
  else
4407
  {
4408
    bool changed = false;
×
4409
    BObjectImp* imp = CallPropertyListMethod( proplist_, methodname, ex, changed );
×
4410
    if ( changed )
×
4411
      set_dirty();
×
4412

4413
    return imp;
×
4414
  }
4415
}
4416

4417
BObjectImp* UObject::custom_script_method( const char* methodname, Core::UOExecutor& ex )
×
4418
{
4419
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4420
  if ( objmethod != nullptr )
×
4421
    return this->script_method_id( objmethod->id, ex );
×
4422
  return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
×
4423
}
4424

4425
BObjectImp* UDoor::get_script_member_id( const int id ) const
×
4426
{
4427
  BObjectImp* imp = ULockable::get_script_member_id( id );
×
4428
  if ( imp != nullptr )
×
4429
    return imp;
×
4430

4431
  switch ( id )
×
4432
  {
4433
  case MBR_ISOPEN:
×
4434
    return new BLong( is_open() ? 1 : 0 );
×
4435
    break;
4436
  default:
×
4437
    return nullptr;
×
4438
  }
4439
}
4440

4441
BObjectImp* UDoor::get_script_member( const char* membername ) const
×
4442
{
4443
  ObjMember* objmember = getKnownObjMember( membername );
×
4444
  if ( objmember != nullptr )
×
4445
    return this->get_script_member_id( objmember->id );
×
4446
  return nullptr;
×
4447
}
4448

4449
BObjectImp* UDoor::script_method_id( const int id, Core::UOExecutor& ex )
×
4450
{
4451
  BObjectImp* imp = base::script_method_id( id, ex );
×
4452
  if ( imp != nullptr )
×
4453
    return imp;
×
4454

4455
  switch ( id )
×
4456
  {
4457
  case MTH_OPEN:
×
4458
    open();
×
4459
    break;
×
4460
  case MTH_CLOSE:
×
4461
    close();
×
4462
    break;
×
4463
  case MTH_TOGGLE:
×
4464
    toggle();
×
4465
    break;
×
4466
  default:
×
4467
    return nullptr;
×
4468
  }
4469
  return new BLong( 1 );
×
4470
}
4471

4472
BObjectImp* UDoor::script_method( const char* methodname, Core::UOExecutor& ex )
×
4473
{
4474
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4475
  if ( objmethod != nullptr )
×
4476
    return this->script_method_id( objmethod->id, ex );
×
4477
  return nullptr;
×
4478
}
4479
}  // namespace Core
4480
namespace Items
4481
{
4482
using namespace Bscript;
4483

4484
BObjectImp* Equipment::get_script_member_id( const int id ) const
7✔
4485
{
4486
  BObjectImp* imp = Item::get_script_member_id( id );
7✔
4487
  if ( imp != nullptr )
7✔
4488
    return imp;
2✔
4489

4490
  switch ( id )
5✔
4491
  {
4492
  case MBR_INTRINSIC:
×
4493
    return new BLong( is_intrinsic() );
×
4494
    break;
4495
  default:
5✔
4496
    return nullptr;
5✔
4497
  }
4498
}
4499
BObjectImp* Equipment::get_script_member( const char* membername ) const
×
4500
{
4501
  ObjMember* objmember = getKnownObjMember( membername );
×
4502
  if ( objmember != nullptr )
×
4503
    return this->get_script_member_id( objmember->id );
×
4504
  return nullptr;
×
4505
}
4506

4507
BObjectImp* Equipment::set_script_member_id( const int id, int value )
3✔
4508
{
4509
  BObjectImp* imp = Item::set_script_member_id( id, value );
3✔
4510
  if ( imp != nullptr )
3✔
4511
    return imp;
×
4512

4513
  return nullptr;
3✔
4514
  /*
4515
  switch(id)
4516
  {
4517
  default: return nullptr;
4518
  }
4519
  */
4520
}
4521
BObjectImp* Equipment::set_script_member( const char* membername, int value )
×
4522
{
4523
  ObjMember* objmember = getKnownObjMember( membername );
×
4524
  if ( objmember != nullptr )
×
4525
    return this->set_script_member_id( objmember->id, value );
×
4526
  return nullptr;
×
4527
}
4528

4529
BObjectImp* Equipment::set_script_member_id_double( const int id, double value )
×
4530
{
4531
  BObjectImp* imp = Item::set_script_member_id_double( id, value );
×
4532
  if ( imp != nullptr )
×
4533
    return imp;
×
4534

4535
  return nullptr;
×
4536
  /*
4537
  switch(id)
4538
  {
4539
  default: return nullptr;
4540
  }
4541
  */
4542
}
4543
BObjectImp* Equipment::set_script_member_double( const char* membername, double value )
×
4544
{
4545
  ObjMember* objmember = getKnownObjMember( membername );
×
4546
  if ( objmember != nullptr )
×
4547
    return this->set_script_member_id_double( objmember->id, value );
×
4548
  return nullptr;
×
4549
}
4550

4551

4552
BObjectImp* UWeapon::get_script_member_id( const int id ) const
4✔
4553
{
4554
  BObjectImp* imp = Equipment::get_script_member_id( id );
4✔
4555
  if ( imp != nullptr )
4✔
4556
    return imp;
1✔
4557

4558
  switch ( id )
3✔
4559
  {
4560
  case MBR_DMG_MOD:
1✔
4561
    return new BLong( damage_mod() );
1✔
4562
    break;
4563
  case MBR_SPEED_MOD:
1✔
4564
    return new BLong( speed_mod() );
1✔
4565
    break;
4566
  case MBR_ATTRIBUTE:
×
4567
    return new String( attribute().name );
×
4568
    break;
4569
  case MBR_HITSCRIPT:
1✔
4570
    return new String( hit_script_.qualifiedname() );
1✔
4571
    break;
4572
  default:
×
4573
    return nullptr;
×
4574
  }
4575
}
4576
BObjectImp* UWeapon::get_script_member( const char* membername ) const
3✔
4577
{
4578
  ObjMember* objmember = getKnownObjMember( membername );
3✔
4579
  if ( objmember != nullptr )
3✔
4580
    return this->get_script_member_id( objmember->id );
3✔
4581
  return nullptr;
×
4582
}
4583

4584
BObjectImp* UWeapon::set_script_member_id( const int id, const std::string& value )
2✔
4585
{
4586
  BObjectImp* imp = Item::set_script_member_id( id, value );
2✔
4587
  if ( imp != nullptr )
2✔
4588
    return imp;
1✔
4589

4590
  switch ( id )
1✔
4591
  {
4592
  case MBR_HITSCRIPT:
1✔
4593
    set_hit_script( value );
1✔
4594
    return new BLong( 1 );
1✔
4595
  default:
×
4596
    return nullptr;
×
4597
  }
4598
}
4599
BObjectImp* UWeapon::set_script_member( const char* membername, const std::string& value )
1✔
4600
{
4601
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4602
  if ( objmember != nullptr )
1✔
4603
    return this->set_script_member_id( objmember->id, value );
1✔
4604
  return nullptr;
×
4605
}
4606

4607
BObjectImp* UWeapon::set_script_member_id( const int id, int value )
2✔
4608
{
4609
  if ( is_intrinsic() )
2✔
4610
    return new BError( "Cannot alter an instrinsic NPC weapon member values" );  // executor won't
×
4611
                                                                                 // return this to
4612
                                                                                 // the script
4613
                                                                                 // currently.
4614

4615
  BObjectImp* imp = Equipment::set_script_member_id( id, value );
2✔
4616
  if ( imp != nullptr )
2✔
4617
    return imp;
×
4618

4619
  switch ( id )
2✔
4620
  {
4621
  case MBR_DMG_MOD:
1✔
4622
    damage_mod( Clib::clamp_convert<s16>( value ) );
1✔
4623
    break;
1✔
4624
  case MBR_SPEED_MOD:
1✔
4625
    speed_mod( Clib::clamp_convert<s16>( value ) );
1✔
4626
    break;
1✔
4627
  default:
×
4628
    return nullptr;
×
4629
  }
4630
  return new BLong( value );
2✔
4631
}
4632

4633
BObjectImp* UWeapon::set_script_member( const char* membername, int value )
2✔
4634
{
4635
  ObjMember* objmember = getKnownObjMember( membername );
2✔
4636
  if ( objmember != nullptr )
2✔
4637
    return this->set_script_member_id( objmember->id, value );
2✔
4638
  return nullptr;
×
4639
}
4640

4641
BObjectImp* UWeapon::set_script_member_id_double( const int id, double value )
×
4642
{
4643
  if ( is_intrinsic() )
×
4644
    return new BError( "Cannot alter an instrinsic NPC weapon member values" );  // executor won't
×
4645
                                                                                 // return this to
4646
                                                                                 // the script
4647
                                                                                 // currently.
4648
  return base::set_script_member_id_double( id, value );
×
4649
}
4650

4651
BObjectImp* UWeapon::set_script_member_double( const char* membername, double value )
×
4652
{
4653
  ObjMember* objmember = getKnownObjMember( membername );
×
4654
  if ( objmember != nullptr )
×
4655
    return this->set_script_member_id_double( objmember->id, value );
×
4656
  return base::set_script_member_double( membername, value );
×
4657
}
4658

4659
BObjectImp* UArmor::get_script_member_id( const int id ) const
3✔
4660
{
4661
  BObjectImp* imp = Equipment::get_script_member_id( id );
3✔
4662
  if ( imp != nullptr )
3✔
4663
    return imp;
1✔
4664

4665
  switch ( id )
2✔
4666
  {
4667
  case MBR_AR_MOD:
1✔
4668
    return new BLong( ar_mod() );
1✔
4669
    break;
4670
  case MBR_AR:
×
4671
    return new BLong( ar() );
×
4672
    break;
4673
  case MBR_AR_BASE:
×
4674
    return new BLong( ar_base() );
×
4675
    break;
4676
  case MBR_ONHIT_SCRIPT:
1✔
4677
    // bad method name? nullptr makes it return the fullpath
4678
    return new String( onhitscript_.qualifiedname() );
1✔
4679
    break;
4680
  default:
×
4681
    return nullptr;
×
4682
  }
4683
}
4684

4685
BObjectImp* UArmor::get_script_member( const char* membername ) const
2✔
4686
{
4687
  ObjMember* objmember = getKnownObjMember( membername );
2✔
4688
  if ( objmember != nullptr )
2✔
4689
    return this->get_script_member_id( objmember->id );
2✔
4690
  return nullptr;
×
4691
}
4692

4693
BObjectImp* UArmor::set_script_member_id( const int id, const std::string& value )
2✔
4694
{
4695
  BObjectImp* imp = Item::set_script_member_id( id, value );
2✔
4696
  if ( imp != nullptr )
2✔
4697
    return imp;
1✔
4698
  switch ( id )
1✔
4699
  {
4700
  case MBR_ONHIT_SCRIPT:
1✔
4701
    set_onhitscript( value );
1✔
4702
    return new BLong( 1 );
1✔
4703
  default:
×
4704
    return nullptr;
×
4705
  }
4706
}
4707

4708
BObjectImp* UArmor::set_script_member( const char* membername, const std::string& value )
1✔
4709
{
4710
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4711
  if ( objmember != nullptr )
1✔
4712
    return this->set_script_member_id( objmember->id, value );
1✔
4713
  return nullptr;
×
4714
}
4715

4716
BObjectImp* UArmor::set_script_member_id( const int id, int value )
1✔
4717
{
4718
  BObjectImp* imp = Equipment::set_script_member_id( id, value );
1✔
4719
  if ( imp != nullptr )
1✔
4720
    return imp;
×
4721

4722
  switch ( id )
1✔
4723
  {
4724
  case MBR_AR_MOD:
1✔
4725
    this->ar_mod( Clib::clamp_convert<s16>( value ) );
1✔
4726
    if ( container != nullptr )
1✔
4727
    {
4728
      if ( Core::IsCharacter( container->serial ) )
×
4729
      {
4730
        Mobile::Character* chr = container->get_chr_owner();
×
4731
        if ( chr != nullptr )
×
4732
          Mobile::ARUpdater::on_change( chr );
×
4733
      }
4734
    }
4735
    return new BLong( value );
1✔
4736
  default:
×
4737
    return nullptr;
×
4738
  }
4739
}
4740

4741
BObjectImp* UArmor::set_script_member( const char* membername, int value )
1✔
4742
{
4743
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4744
  if ( objmember != nullptr )
1✔
4745
    return this->set_script_member_id( objmember->id, value );
1✔
4746
  return nullptr;
×
4747
}
4748
}  // namespace Items
4749
namespace Module
4750
{
4751
using namespace Bscript;
4752

4753
const char* EClientRefObjImp::typeOf() const
×
4754
{
4755
  return "ClientRef";
×
4756
}
4757

4758
u8 EClientRefObjImp::typeOfInt() const
×
4759
{
4760
  return OTClientRef;
×
4761
}
4762

4763
BObjectImp* EClientRefObjImp::copy() const
×
4764
{
4765
  if ( value().exists() )
×
4766
    return value()->make_ref();
×
4767
  return new BError( "Client is disconnected" );
×
4768
}
4769

4770
bool EClientRefObjImp::isTrue() const
2✔
4771
{
4772
  return ( value().exists() && value()->isConnected() );
2✔
4773
}
4774

4775
bool EClientRefObjImp::operator==( const BObjectImp& objimp ) const
×
4776
{
4777
  if ( objimp.isa( BObjectImp::OTApplicObj ) )
×
4778
  {
4779
    const BApplicObjBase* aob =
4780
        Clib::explicit_cast<const BApplicObjBase*, const BObjectImp*>( &objimp );
×
4781

4782
    if ( aob->object_type() == &eclientrefobjimp_type )
×
4783
    {
4784
      const EClientRefObjImp* clientref_imp =
4785
          Clib::explicit_cast<const EClientRefObjImp*, const BApplicObjBase*>( aob );
×
4786

4787
      if ( clientref_imp->value().exists() && value().exists() &&
×
4788
           ( clientref_imp->value()->chr != nullptr ) && ( value()->chr != nullptr ) )
×
4789
        return ( clientref_imp->value()->chr->serial == value()->chr->serial );
×
4790
      return false;
×
4791
    }
4792
    return false;
×
4793
  }
4794
  else if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
×
4795
    return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
×
4796
  return false;
×
4797
}
4798

4799
BObjectRef EClientRefObjImp::get_member_id( const int id )
5✔
4800
{
4801
  if ( ( !obj_.exists() ) || ( !obj_->isConnected() ) )
5✔
4802
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4803

4804
  BObjectImp* result = obj_->get_script_member_id( id );
5✔
4805
  if ( result != nullptr )
5✔
4806
    return BObjectRef( result );
4✔
4807
  return BObjectRef( UninitObject::create() );
1✔
4808
}
4809

4810
BObjectRef EClientRefObjImp::get_member( const char* membername )
1✔
4811
{
4812
  if ( ( !obj_.exists() ) || ( !obj_->isConnected() ) )
1✔
4813
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4814
  ObjMember* objmember = getKnownObjMember( membername );
1✔
4815
  if ( objmember != nullptr )
1✔
4816
    return this->get_member_id( objmember->id );
×
4817
  return BObjectRef( UninitObject::create() );
1✔
4818
}
4819

4820
BObjectRef EClientRefObjImp::set_member( const char* membername, BObjectImp* value, bool copy )
×
4821
{
4822
  if ( !obj_.exists() || !obj_->isConnected() )
×
4823
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4824
  ObjMember* objmember = getKnownObjMember( membername );
×
4825
  if ( objmember != nullptr )
×
4826
    return this->set_member_id( objmember->id, value, copy );
×
4827
  return BObjectRef( UninitObject::create() );
×
4828
}
4829

4830
BObjectRef EClientRefObjImp::set_member_id( const int id, BObjectImp* value, bool /*copy*/ )
2✔
4831
{
4832
  if ( !obj_.exists() || !obj_->isConnected() )
2✔
4833
    return BObjectRef( new BError( "Client not ready or disconnected" ) );
×
4834

4835
  BObjectImp* result = nullptr;
2✔
4836
  if ( auto* v = impptrIf<BLong>( value ) )
2✔
4837
    result = obj_->set_script_member_id( id, v->value() );
2✔
4838

4839
  if ( result != nullptr )
2✔
4840
    return BObjectRef( result );
2✔
4841

4842
  return BObjectRef( UninitObject::create() );
×
4843
}
4844

4845

4846
BObjectImp* EClientRefObjImp::call_polmethod( const char* methodname, Core::UOExecutor& ex )
×
4847
{
4848
  if ( !obj_.exists() || !obj_->isConnected() )
×
4849
    return new BError( "Client not ready or disconnected" );
×
4850
  bool forcebuiltin{ Executor::builtinMethodForced( methodname ) };
×
4851
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
4852
  if ( objmethod != nullptr )
×
4853
    return this->call_polmethod_id( objmethod->id, ex, forcebuiltin );
×
4854
  return Core::gamestate.system_hooks.call_script_method( methodname, &ex, this );
×
4855
}
4856

4857
BObjectImp* EClientRefObjImp::call_polmethod_id( const int id, Core::UOExecutor& ex,
×
4858
                                                 bool forcebuiltin )
4859
{
4860
  if ( !obj_.exists() || !obj_->isConnected() )
×
4861
    return new BError( "Client not ready or disconnected" );
×
4862

4863
  ObjMethod* mth = getObjMethod( id );
×
4864
  if ( mth->overridden && !forcebuiltin )
×
4865
  {
4866
    auto* imp = Core::gamestate.system_hooks.call_script_method( mth->code, &ex, this );
×
4867
    if ( imp )
×
4868
      return imp;
×
4869
  }
4870
  switch ( id )
×
4871
  {
4872
  case MTH_COMPAREVERSION:
×
4873
  {
4874
    if ( !ex.hasParams( 1 ) )
×
4875
      return new BError( "Not enough parameters" );
×
4876
    const String* pstr;
4877
    if ( ex.getStringParam( 0, pstr ) )
×
4878
      return new BLong( obj_->compareVersion( pstr->getStringRep() ) ? 1 : 0 );
×
4879
    return new BError( "Invalid parameter type" );
×
4880
  }
4881
  }
4882

4883
  return base::call_polmethod_id( id, ex );
×
4884
}
4885

4886
BoatMovementEvent::BoatMovementEvent( Mobile::Character* source, const u8 speed, const u8 direction,
3✔
4887
                                      const u8 relative_direction )
3✔
4888
{
4889
  addMember( "type", new BLong( Core::EVID_BOAT_MOVEMENT ) );
3✔
4890
  addMember( "source", new Module::EOfflineCharacterRefObjImp( source ) );
3✔
4891
  addMember( "speed", new BLong( static_cast<int>( speed ) ) );
3✔
4892
  addMember( "direction", new BLong( static_cast<int>( direction ) ) );
3✔
4893
  addMember( "relative_direction", new BLong( static_cast<int>( relative_direction ) ) );
3✔
4894
}
3✔
4895

4896
SourcedEvent::SourcedEvent( Core::EVENTID type, Mobile::Character* source )
20✔
4897
{
4898
  addMember( "type", new BLong( type ) );
20✔
4899
  addMember( "source", new Module::EOfflineCharacterRefObjImp( source ) );
20✔
4900
}
20✔
4901

4902
SpeechEvent::SpeechEvent( Mobile::Character* speaker, const std::string& speech,
3✔
4903
                          const std::string& texttype, std::string lang,
4904
                          Bscript::ObjArray* speechtokens )
3✔
4905
{
4906
  addMember( "type", new BLong( Core::EVID_SPOKE ) );
3✔
4907
  addMember( "source", new Module::EOfflineCharacterRefObjImp( speaker ) );
3✔
4908
  addMember( "text", new String( speech ) );
3✔
4909
  addMember( "texttype", new String( texttype ) );
3✔
4910
  if ( !lang.empty() )
3✔
4911
    addMember( "langcode", new String( lang ) );
3✔
4912
  if ( speechtokens != nullptr )
3✔
4913
    addMember( "tokens", new Bscript::ObjArray( *speechtokens ) );
3✔
4914
}
3✔
4915

4916
DamageEvent::DamageEvent( Mobile::Character* source, unsigned short damage )
×
4917
{
4918
  addMember( "type", new BLong( Core::EVID_DAMAGED ) );
×
4919

4920
  if ( source != nullptr )
×
4921
    addMember( "source", new Module::EOfflineCharacterRefObjImp( source ) );
×
4922
  else
4923
    addMember( "source", new BLong( 0 ) );
×
4924

4925
  addMember( "damage", new BLong( damage ) );
×
4926
}
×
4927

4928
ItemGivenEvent::ItemGivenEvent( Mobile::Character* chr_givenby, Items::Item* item_given,
×
4929
                                Mobile::NPC* chr_givento )
×
4930
    : SourcedEvent( Core::EVID_ITEM_GIVEN, chr_givenby ), given_by_( nullptr )
×
4931
{
4932
  addMember( "item", new EItemRefObjImp( item_given ) );
×
4933

4934
  given_time_ = Core::read_gameclock();
×
4935
  item_.set( item_given );
×
4936
  cont_.set( item_given->container );
×
4937
  given_by_.set( chr_givenby );
×
4938

4939
  item_given->setprop( "GivenBy", BLong::pack( chr_givenby->serial ) );
×
4940
  item_given->setprop( "GivenTo", BLong::pack( chr_givento->serial ) );
×
4941
  item_given->setprop( "GivenTime", BLong::pack( given_time_ ) );
×
4942
}
×
4943

4944
ItemGivenEvent::~ItemGivenEvent()
×
4945
{
4946
  /* See if the item is still in the container it was in
4947
       This means the AI script didn't do anything with it.
4948
       */
4949
  Items::Item* item = item_.get();
×
4950
  Core::UContainer* cont = cont_.get();
×
4951
  Mobile::Character* chr = given_by_.get();
×
4952

4953
  std::string given_time_str;
×
4954
  if ( !item->getprop( "GivenTime", given_time_str ) )
×
4955
    given_time_str = "";
×
4956

4957
  item->eraseprop( "GivenBy" );
×
4958
  item->eraseprop( "GivenTo" );
×
4959
  item->eraseprop( "GivenTime" );
×
4960

4961
  Bscript::BObject given_value( BObjectImp::unpack( given_time_str.c_str() ) );
×
4962
  int gts = given_value.impptr<BLong>()->value();
×
4963

4964
  if ( item->orphan() || cont->orphan() || chr->orphan() )
×
4965
    return;
×
4966

4967
  if ( item->container == cont && Clib::tostring( given_time_ ) == Clib::tostring( gts ) )
×
4968
  {
4969
    Core::UContainer* backpack = chr->backpack();
×
4970
    if ( backpack != nullptr && !chr->dead() )
×
4971
    {
4972
      if ( backpack->can_add( *item ) )
×
4973
      {
4974
        cont->remove( item );
×
4975
        u8 newSlot = 1;
×
4976
        if ( !backpack->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
×
4977
        {
4978
          item->setposition( chr->pos() );
×
4979
          add_item_to_world( item );
×
4980
          register_with_supporting_multi( item );
×
4981
          move_item( item, item->pos() );
×
4982
          return;
×
4983
        }
4984
        backpack->add( item, item->pos2d() );
×
4985
        update_item_to_inrange( item );
×
4986
        return;
×
4987
      }
4988
    }
4989
    cont->remove( item );
×
4990
    item->setposition( chr->pos() );
×
4991
    add_item_to_world( item );
×
4992
    register_with_supporting_multi( item );
×
4993
    move_item( item, item->pos() );
×
4994
  }
4995
}
×
4996
}  // namespace Module
4997

4998
namespace Network
4999
{
5000
using namespace Bscript;
5001
BObjectImp* Client::set_script_member_id( const int id, int value )
2✔
5002
{
5003
  switch ( id )
2✔
5004
  {
5005
  case MBR_DISABLE_INACTIVITY_TIMEOUT:
×
5006
    disable_inactivity_timeout( value );
×
5007
    return new BLong( disable_inactivity_timeout() );
×
5008
  case MBR_VISUAL_RANGE:
2✔
5009
    set_update_range_by_script( Clib::clamp_convert<u8>( value ) );
2✔
5010
    return new BLong( update_range() );
2✔
5011
  default:
×
5012
    return nullptr;
×
5013
  }
5014
}
5015

5016
BObjectImp* Client::get_script_member_id( const int id )
5✔
5017
{
5018
  switch ( id )
5✔
5019
  {
5020
  case MBR_ACCTNAME:
2✔
5021
    if ( acct != nullptr )
2✔
5022
      return new String( acct->name() );
2✔
5023
    return new BError( "Not attached to an account" );
×
5024
    break;
5025
  case MBR_ACCT:
2✔
5026
    if ( acct != nullptr )
2✔
5027
      return new Accounts::AccountObjImp( Accounts::AccountPtrHolder( Core::AccountRef( acct ) ) );
2✔
5028
    return new BError( "Not attached to an account" );
×
5029
    break;
5030
  case MBR_IP:
×
5031
    return new String( ipaddrAsString() );
×
5032
    break;
5033
  case MBR_CLIENTVERSION:
×
5034
    return new String( getversion() );
×
5035
    break;
5036
  case MBR_CLIENTVERSIONDETAIL:
×
5037
  {
5038
    std::unique_ptr<BStruct> info( new BStruct );
×
5039
    Network::VersionDetailStruct version = getversiondetail();
×
5040
    info->addMember( "major", new BLong( version.major ) );
×
5041
    info->addMember( "minor", new BLong( version.minor ) );
×
5042
    info->addMember( "rev", new BLong( version.rev ) );
×
5043
    info->addMember( "patch", new BLong( version.patch ) );
×
5044
    return info.release();
×
5045
  }
×
5046
  break;
5047
  case MBR_CLIENTINFO:
×
5048
    return getclientinfo();
×
5049
    break;
5050
  case MBR_CLIENTTYPE:
×
5051
    return new BLong( ClientType );
×
5052
    break;
5053
  case MBR_UO_EXPANSION_CLIENT:
×
5054
    return new BLong( UOExpansionFlagClient );
×
5055
    break;
5056
  case MBR_LAST_ACTIVITY_AT:
×
5057
    return new BLong( static_cast<s32>( last_activity_at() ) );
×
5058
    break;
5059
  case MBR_LAST_PACKET_AT:
×
5060
    return new BLong( static_cast<s32>( last_packet_at() ) );
×
5061
    break;
5062
  case MBR_PORT:
×
5063
    return new BLong( listen_port );
×
5064
    break;
5065
  case MBR_DISABLE_INACTIVITY_TIMEOUT:
×
5066
    return new BLong( disable_inactivity_timeout() );
×
5067
    break;
5068
  case MBR_VISUAL_RANGE:
×
5069
    return new BLong( update_range() );
×
5070
    break;
5071
  }
5072

5073
  return nullptr;
1✔
5074
}
5075

5076
}  // namespace Network
5077

5078
namespace Core
5079
{
5080
bool UObject::script_isa( unsigned isatype ) const
6,238✔
5081
{
5082
  return ( isatype == POLCLASS_OBJECT );
6,238✔
5083
}
5084

5085
bool ULockable::script_isa( unsigned isatype ) const
123✔
5086
{
5087
  return ( isatype == POLCLASS_LOCKABLE ) || base::script_isa( isatype );
123✔
5088
}
5089

5090
bool UContainer::script_isa( unsigned isatype ) const
171✔
5091
{
5092
  return ( isatype == POLCLASS_CONTAINER ) || base::script_isa( isatype );
171✔
5093
}
5094

5095
bool UCorpse::script_isa( unsigned isatype ) const
71✔
5096
{
5097
  return ( isatype == POLCLASS_CORPSE ) || base::script_isa( isatype );
71✔
5098
}
5099

5100
bool UDoor::script_isa( unsigned isatype ) const
×
5101
{
5102
  return ( isatype == POLCLASS_DOOR ) || base::script_isa( isatype );
×
5103
}
5104

5105
bool Spellbook::script_isa( unsigned isatype ) const
×
5106
{
5107
  return ( isatype == POLCLASS_SPELLBOOK ) || base::script_isa( isatype );
×
5108
}
5109

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

5116
namespace Items
5117
{
5118
bool Item::script_isa( unsigned isatype ) const
6,225✔
5119
{
5120
  return ( isatype == Core::POLCLASS_ITEM ) || base::script_isa( isatype );
6,225✔
5121
}
5122

5123
bool Equipment::script_isa( unsigned isatype ) const
×
5124
{
5125
  return ( isatype == Core::POLCLASS_EQUIPMENT ) || base::script_isa( isatype );
×
5126
}
5127

5128
bool UArmor::script_isa( unsigned isatype ) const
×
5129
{
5130
  return ( isatype == Core::POLCLASS_ARMOR ) || base::script_isa( isatype );
×
5131
}
5132

5133
bool UWeapon::script_isa( unsigned isatype ) const
×
5134
{
5135
  return ( isatype == Core::POLCLASS_WEAPON ) || base::script_isa( isatype );
×
5136
}
5137
}  // namespace Items
5138

5139
namespace Mobile
5140
{
5141
bool Character::script_isa( unsigned isatype ) const
138✔
5142
{
5143
  return ( isatype == Core::POLCLASS_MOBILE ) || base::script_isa( isatype );
138✔
5144
}
5145

5146
bool NPC::script_isa( unsigned isatype ) const
56✔
5147
{
5148
  return ( isatype == Core::POLCLASS_NPC ) || base::script_isa( isatype );
56✔
5149
}
5150
}  // namespace Mobile
5151
namespace Multi
5152
{
5153
bool UMulti::script_isa( unsigned isatype ) const
3✔
5154
{
5155
  return ( isatype == Core::POLCLASS_MULTI ) || base::script_isa( isatype );
3✔
5156
}
5157

5158
bool UMulti::setgraphic( u16 /* newobjtype */ )
×
5159
{
5160
  return false;
×
5161
}
5162

5163
bool UBoat::script_isa( unsigned isatype ) const
9✔
5164
{
5165
  return ( isatype == Core::POLCLASS_BOAT ) || base::script_isa( isatype );
9✔
5166
}
5167

5168
bool UHouse::script_isa( unsigned isatype ) const
×
5169
{
5170
  return ( isatype == Core::POLCLASS_HOUSE ) || base::script_isa( isatype );
×
5171
}
5172
}  // namespace Multi
5173
}  // 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