Pol  Revision:cb584c9
npcmod.cpp
Go to the documentation of this file.
1 
7 #include "npcmod.h"
8 
9 #include <iostream>
10 #include <stddef.h>
11 #include <string>
12 
13 #include "../../bscript/berror.h"
14 #include "../../bscript/bobject.h"
15 #include "../../bscript/impstr.h"
16 #include "../../clib/clib.h"
17 #include "../../clib/compilerspecifics.h"
18 #include "../../clib/logfacility.h"
19 #include "../../clib/random.h"
20 #include "../../clib/rawtypes.h"
21 #include "../../clib/stlutil.h"
22 #include "../../clib/strutil.h"
23 #include "../containr.h"
24 #include "../item/item.h"
25 #include "../mobile/boundbox.h"
26 #include "../mobile/charactr.h"
27 #include "../mobile/npc.h"
28 #include "../mobile/ufacing.h"
29 #include "../network/packethelper.h"
30 #include "../network/packets.h"
31 #include "../objtype.h"
32 #include "../pktdef.h"
33 #include "../poltype.h"
34 #include "../unicode.h"
35 #include "../uoscrobj.h"
36 #include "../uworld.h"
37 #include "osmod.h"
38 #include "unimod.h"
39 
40 namespace Pol
41 {
42 namespace Bscript
43 {
44 using namespace Module;
45 template <>
48  {"Wander", &NPCExecutorModule::mf_Wander},
49  {"self", &NPCExecutorModule::mf_Self},
50  {"face", &NPCExecutorModule::face},
51  {"move", &NPCExecutorModule::move},
52  {"WalkToward", &NPCExecutorModule::mf_WalkToward},
53  {"RunToward", &NPCExecutorModule::mf_RunToward},
54  {"WalkAwayFrom", &NPCExecutorModule::mf_WalkAwayFrom},
55  {"RunAwayFrom", &NPCExecutorModule::mf_RunAwayFrom},
56  {"TurnToward", &NPCExecutorModule::mf_TurnToward},
57  {"TurnAwayFrom", &NPCExecutorModule::mf_TurnAwayFrom},
58 
59  {"WalkTowardLocation", &NPCExecutorModule::mf_WalkTowardLocation},
60  {"RunTowardLocation", &NPCExecutorModule::mf_RunTowardLocation},
61  {"WalkAwayFromLocation", &NPCExecutorModule::mf_WalkAwayFromLocation},
62  {"RunAwayFromLocation", &NPCExecutorModule::mf_RunAwayFromLocation},
63  {"TurnTowardLocation", &NPCExecutorModule::mf_TurnTowardLocation},
64  {"TurnAwayFromLocation", &NPCExecutorModule::mf_TurnAwayFromLocation},
65 
66  {"say", &NPCExecutorModule::say},
67  {"SayUC", &NPCExecutorModule::SayUC},
68  {"SetOpponent", &NPCExecutorModule::mf_SetOpponent},
69  {"SetWarMode", &NPCExecutorModule::mf_SetWarMode},
70  {"SetAnchor", &NPCExecutorModule::mf_SetAnchor},
71  {"position", &NPCExecutorModule::position},
72  {"facing", &NPCExecutorModule::facing},
73  {"IsLegalMove", &NPCExecutorModule::IsLegalMove},
74  {"CanMove", &NPCExecutorModule::CanMove},
75  {"getproperty", &NPCExecutorModule::getproperty},
76  {"setproperty", &NPCExecutorModule::setproperty},
77  {"makeboundingbox", &NPCExecutorModule::makeboundingbox}
78  // { "CreateBackpack", CreateBackpack },
79  // { "CreateItem", CreateItem }
80 };
81 } // namespace Bscript
82 
83 namespace Module
84 {
85 using namespace Bscript;
87  : TmplExecutorModule<NPCExecutorModule>( "NPC", ex ), npcref( &npc ), npc( npc )
88 {
89  os_module = static_cast<OSExecutorModule*>( exec.findModule( "OS" ) );
90  if ( os_module == nullptr )
91  throw std::runtime_error( "NPCExecutorModule needs OS module!" );
92 }
93 
95 {
96  if ( npc.ex == &exec )
97  npc.ex = nullptr;
98 }
99 
101 
102 class BoundingBoxObjImp : public BApplicObj<Mobile::BoundingBox>
103 {
104 public:
105  BoundingBoxObjImp() : BApplicObj<Mobile::BoundingBox>( &bounding_box_type ) {}
107  : BApplicObj<Mobile::BoundingBox>( &bounding_box_type, b )
108  {
109  }
110  virtual const char* typeOf() const POL_OVERRIDE { return "BoundingBox"; }
111  virtual u8 typeOfInt() const POL_OVERRIDE { return OTBoundingBox; }
112  virtual BObjectImp* copy() const POL_OVERRIDE { return new BoundingBoxObjImp( value() ); }
113 };
114 
115 /* IsLegalMove: parameters (move, bounding box)*/
117 {
118  String* facing_str = static_cast<String*>( exec.getParamImp( 0, BObjectImp::OTString ) );
119  BApplicObjBase* appobj =
121  if ( facing_str == nullptr || appobj == nullptr || appobj->object_type() != &bounding_box_type )
122  {
123  return new BLong( 0 );
124  }
125 
127  static_cast<BApplicObj<Mobile::BoundingBox>*>( appobj );
128  const Mobile::BoundingBox& bbox = ao_bbox->value();
129 
131  if ( Mobile::DecodeFacing( facing_str->value().c_str(), facing ) == false )
132  return new BLong( 0 );
133 
134  unsigned short x, y;
135  npc.getpos_ifmove( facing, &x, &y );
136 
137  return new BLong( bbox.contains( x, y ) );
138 }
139 
140 /* CanMove: parameters (facing)*/
142 {
143  if ( exec.fparams.size() == 1 )
144  {
145  BObjectImp* param0 = exec.getParamImp( 0 );
146 
147  if ( param0->isa( BObjectImp::OTString ) )
148  {
149  const char* dir = exec.paramAsString( 0 );
151 
152  if ( Mobile::DecodeFacing( dir, facing ) == false )
153  {
154  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
155  << "\tCall to function npc::canmove():\n"
156  << "\tParameter 0: Expected direction: N S E W NW NE SW SE, got " << dir << "\n";
157  return new BError( "Invalid facing value" );
158  }
159 
160  return new BLong( npc.could_move( facing ) ? 1 : 0 );
161  }
162  else if ( param0->isa( BObjectImp::OTLong ) )
163  {
164  BLong* blong = static_cast<BLong*>( param0 );
165  Core::UFACING facing = static_cast<Core::UFACING>( blong->value() & PKTIN_02_FACING_MASK );
166  return new BLong( npc.could_move( facing ) ? 1 : 0 );
167  }
168  else
169  {
170  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
171  << "\tCall to function npc::canmove():\n"
172  << "\tParameter 0: Expected direction, got datatype "
173  << BObjectImp::typestr( param0->type() ) << "\n";
174  return new BError( "Invalid parameter type" );
175  }
176  }
177  else
178  return new BError( "Invalid parameter count" );
179 }
180 
182 {
183  return new ECharacterRefObjImp( &npc );
184 }
185 
187 {
188  Core::xcoord x;
189  Core::ycoord y;
190  int dstart, psub;
191  if ( getParam( 0, x ) && getParam( 1, y ) && getParam( 2, dstart ) && getParam( 3, psub ) )
192  {
193  if ( !npc.realm->valid( x, y, 0 ) )
194  return new BError( "Invalid Coordinates for Realm" );
195  if ( dstart )
196  {
197  npc.anchor.enabled = true;
198  npc.anchor.x = static_cast<unsigned short>( x );
199  npc.anchor.y = static_cast<unsigned short>( y );
200  npc.anchor.dstart = static_cast<unsigned short>( dstart );
201  npc.anchor.psub = static_cast<unsigned short>( psub );
202  return new BLong( 1 );
203  }
204  else
205  {
206  npc.anchor.enabled = false;
207  return new BLong( 1 );
208  }
209  }
210  else
211  {
212  return new BError( "Invalid parameter type" );
213  }
214 }
215 
216 
218 {
219  bool success = false;
220  int dir = facing;
221  if ( run )
222  dir |= 0x80; // FIXME HARDCODE
223 
224  if ( npc.could_move( facing ) )
225  {
226  if ( npc.move(
227  static_cast<unsigned char>( dir ) ) ) // this could still fail, if paralyzed or frozen
228  {
229  npc.tellmove();
230  // move was successful
231  success = true;
232  }
233  // else, npc could move, but move failed.
234  }
235  // else npc could not move
236 
237  return success;
238 }
239 
241 {
242  bool success = false;
243  int dir = facing;
244 
245  if ( run )
246  dir |= 0x80; // FIXME HARDCODE
247 
248  if ( adjust_ok )
249  {
250  if ( npc.use_adjustments() )
251  {
252  for ( int adjust : Core::adjustments )
253  {
254  facing = static_cast<Core::UFACING>( ( dir + adjust ) & 7 );
255 
256  success = _internal_move( facing, run );
257  if ( success == true )
258  break;
259  }
260  }
261  else
262  {
263  success = _internal_move( facing, run );
264  }
265  }
266  else
267  {
268  if ( npc.anchor_allows_move( facing ) && npc.move( static_cast<unsigned char>( dir ) ) )
269  {
270  npc.tellmove();
271  success = true;
272  }
273  }
274 
275  // int base = 1000 - npc.dexterity() * 3;
276  int base = 1000 - npc.run_speed * 3;
277  if ( base < 250 )
278  base = 250;
279  os_module->SleepForMs( run ? ( base / 2 ) : base );
280 
281  // return new String( FacingStr(facing) );
282  return new BLong( success ? 1 : 0 );
283 }
284 
286 {
287  u8 newfacing = 0;
288  bool adjust_ok = true;
289  switch ( Clib::random_int( 7 ) )
290  {
291  case 0:
292  case 1:
293  case 2:
294  case 3:
295  case 4:
296  case 5:
297  newfacing = npc.facing;
298  break;
299  case 6:
300  newfacing = ( static_cast<int>( npc.facing ) - 1 ) & PKTIN_02_FACING_MASK;
301  adjust_ok = false;
302  break;
303  case 7:
304  newfacing = ( static_cast<int>( npc.facing ) + 1 ) & PKTIN_02_FACING_MASK;
305  adjust_ok = false;
306  break;
307  }
308  return move_self( static_cast<Core::UFACING>( newfacing ), false, adjust_ok );
309 }
310 
312 {
313  BObjectImp* param0 = exec.getParamImp( 0 );
314  int flags;
315 
316  if ( param0 == nullptr || !exec.getParam( 1, flags ) )
317  return new BError( "Invalid parameter type." );
318 
319  Core::UFACING i_facing;
320 
321  if ( param0->isa( BObjectImp::OTString ) )
322  {
323  const char* dir = exec.paramAsString( 0 );
324 
325  if ( Mobile::DecodeFacing( dir, i_facing ) == false )
326  {
327  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
328  << "\tCall to function npc::face():\n"
329  << "\tParameter 0: Expected direction: N S E W NW NE SW SE, got " << dir << "\n";
330  return nullptr;
331  }
332  }
333  else if ( param0->isa( BObjectImp::OTLong ) )
334  {
335  BLong* blong = static_cast<BLong*>( param0 );
336  i_facing = static_cast<Core::UFACING>( blong->value() & PKTIN_02_FACING_MASK );
337  }
338  else
339  {
340  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
341  << "\tCall to function npc::face():\n"
342  << "\tParameter 0: Expected direction, "
343  << ", got datatype " << BObjectImp::typestr( param0->type() ) << "\n";
344 
345  return nullptr;
346  }
347 
348  if ( !npc.face( i_facing, flags ) )
349  return new BLong( 0 );
350 
352  return new BLong( i_facing );
353 }
354 
356 {
357  BObjectImp* param0 = exec.getParamImp( 0 );
358 
359  if ( param0->isa( BObjectImp::OTString ) )
360  {
361  const char* dir = exec.paramAsString( 0 );
363 
364  if ( Mobile::DecodeFacing( dir, facing ) == false )
365  {
366  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
367  << "\tCall to function npc::move():\n"
368  << "\tParameter 0: Expected direction: N S E W NW NE SW SE, got " << dir << "\n";
369  return nullptr;
370  }
371 
372  return move_self( facing, false );
373  }
374  else if ( param0->isa( BObjectImp::OTLong ) )
375  {
376  BLong* blong = static_cast<BLong*>( param0 );
377  Core::UFACING facing = static_cast<Core::UFACING>( blong->value() & PKTIN_02_FACING_MASK );
378  return move_self( facing, false );
379  }
380  else if ( param0->isa( BObjectImp::OTApplicObj ) )
381  {
382  BApplicObjBase* appobj = static_cast<BApplicObjBase*>( param0 );
383  if ( appobj->object_type() == &bounding_box_type )
384  {
386  static_cast<BApplicObj<Mobile::BoundingBox>*>( appobj );
387  const Mobile::BoundingBox& bbox = ao_bbox->value();
389 
390  unsigned short x, y;
391  npc.getpos_ifmove( facing, &x, &y );
392  if ( bbox.contains( x, y ) || !bbox.contains( npc.x, npc.y ) )
393  {
394  npc.move( static_cast<unsigned char>( facing ) );
395  npc.tellmove();
396  os_module->SleepFor( 1 );
397  return new String( Mobile::FacingStr( facing ) );
398  }
399  else
400  {
401  return new String( "" );
402  }
403  }
404  else
405  {
406  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
407  << "\tCall to function npc::move():\n"
408  << "\tParameter 0: Expected direction or bounding box, "
409  << ", got datatype " << BObjectImp::typestr( param0->type() ) << "\n";
410  return nullptr;
411  }
412  }
413  else
414  {
415  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
416  << "\tCall to function npc::move():\n"
417  << "\tParameter 0: Expected direction or bounding box, "
418  << ", got datatype " << BObjectImp::typestr( param0->type() ) << "\n";
419 
420  return nullptr;
421  }
422 }
423 
425 {
426  Core::UObject* obj;
427  if ( getUObjectParam( exec, 0, obj ) )
428  {
429  if ( obj->ismobile() )
430  {
431  Mobile::Character* chr = static_cast<Mobile::Character*>( obj );
432  if ( !npc.is_visible_to_me( chr ) )
433  return new BError( "Mobile specified cannot be seen" );
434  }
435  Core::UFACING fac = direction_toward( &npc, obj );
436  return move_self( fac, false, true );
437  }
438  else
439  {
440  return new BError( "Invalid parameter type" );
441  }
442 }
443 
444 
446 {
447  Core::UObject* obj;
448  if ( getUObjectParam( exec, 0, obj ) )
449  {
450  if ( obj->ismobile() )
451  {
452  Mobile::Character* chr = static_cast<Mobile::Character*>( obj );
453  if ( !npc.is_visible_to_me( chr ) )
454  return new BError( "Mobile specified cannot be seen" );
455  }
456  return move_self( direction_toward( &npc, obj ), true, true );
457  }
458  else
459  {
460  return new BError( "Invalid parameter type" );
461  }
462 }
463 
465 {
466  Core::UObject* obj;
467  if ( getUObjectParam( exec, 0, obj ) )
468  {
469  if ( obj->ismobile() )
470  {
471  Mobile::Character* chr = static_cast<Mobile::Character*>( obj );
472  if ( !npc.is_visible_to_me( chr ) )
473  return new BError( "Mobile specified cannot be seen" );
474  }
475  return move_self( direction_away( &npc, obj ), false, true );
476  }
477  else
478  {
479  return new BError( "Invalid parameter type" );
480  }
481 }
482 
484 {
485  Core::UObject* obj;
486  if ( getUObjectParam( exec, 0, obj ) )
487  {
488  if ( obj->ismobile() )
489  {
490  Mobile::Character* chr = static_cast<Mobile::Character*>( obj );
491  if ( !npc.is_visible_to_me( chr ) )
492  return new BError( "Mobile specified cannot be seen" );
493  }
494  return move_self( direction_away( &npc, obj ), true, true );
495  }
496  else
497  {
498  return new BError( "Invalid parameter type" );
499  }
500 }
501 
503 {
504  Core::UObject* obj;
505  int flags;
506 
507  if ( !getUObjectParam( exec, 0, obj ) || !exec.getParam( 1, flags ) )
508  {
509  return new BError( "Invalid parameter type" );
510  }
511 
512  if ( obj->ismobile() )
513  {
514  Mobile::Character* chr = static_cast<Mobile::Character*>( obj );
515  if ( !npc.is_visible_to_me( chr ) )
516  return new BError( "Mobile specified cannot be seen" );
517  }
518 
520  if ( facing == npc.facing )
521  return new BLong( 0 ); // nothing to do here, I'm already facing that direction
522 
523  if ( !npc.face( facing, flags ) )
524  return new BLong( 0 ); // Uh-oh, seems that I can't move to face that
525 
527  return new BLong( 1 );
528 }
529 
531 {
532  Core::UObject* obj;
533  int flags;
534 
535  if ( !getUObjectParam( exec, 0, obj ) || !exec.getParam( 1, flags ) )
536  {
537  return new BError( "Invalid parameter type" );
538  }
539 
540 
541  if ( obj->ismobile() )
542  {
543  Mobile::Character* chr = static_cast<Mobile::Character*>( obj );
544  if ( !npc.is_visible_to_me( chr ) )
545  return new BError( "Mobile specified cannot be seen" );
546  }
547 
549  if ( facing == npc.facing )
550  return new BLong( 0 ); // nothing to do here
551 
552  if ( !npc.face( facing, flags ) )
553  return new BLong( 0 ); // couldn't move for some reason
554 
556  return new BLong( 1 );
557 }
558 
560 {
561  Core::xcoord x;
562  Core::ycoord y;
563  if ( exec.getParam( 0, x ) && exec.getParam( 1, y ) )
564  {
565  if ( !npc.realm->valid( x, y, npc.z ) )
566  return new BError( "Invalid Coordinates for Realm" );
567  Core::UFACING fac = direction_toward( &npc, x, y );
568  return move_self( fac, false, true );
569  }
570  else
571  {
572  return new BError( "Invalid parameter type" );
573  }
574 }
575 
577 {
578  Core::xcoord x;
579  Core::ycoord y;
580 
581  if ( exec.getParam( 0, x ) && exec.getParam( 1, y ) )
582  {
583  if ( !npc.realm->valid( x, y, npc.z ) )
584  return new BError( "Invalid Coordinates for Realm" );
585  Core::UFACING fac = direction_toward( &npc, x, y );
586  return move_self( fac, true, true );
587  }
588  else
589  {
590  return new BError( "Invalid parameter type" );
591  }
592 }
593 
595 {
596  Core::xcoord x;
597  Core::ycoord y;
598  if ( exec.getParam( 0, x ) && exec.getParam( 1, y ) )
599  {
600  if ( !npc.realm->valid( x, y, npc.z ) )
601  return new BError( "Invalid Coordinates for Realm" );
602  Core::UFACING fac = direction_away( &npc, x, y );
603  return move_self( fac, false, true );
604  }
605  else
606  {
607  return new BError( "Invalid parameter type" );
608  }
609 }
610 
612 {
613  Core::xcoord x;
614  Core::ycoord y;
615  if ( exec.getParam( 0, x ) && exec.getParam( 1, y ) )
616  {
617  if ( !npc.realm->valid( x, y, npc.z ) )
618  return new BError( "Invalid Coordinates for Realm" );
619  Core::UFACING fac = direction_away( &npc, x, y );
620  return move_self( fac, true, true );
621  }
622  else
623  {
624  return new BError( "Invalid parameter type" );
625  }
626 }
627 
629 {
630  Core::xcoord x;
631  Core::ycoord y;
632  int flags;
633 
634  if ( !exec.getParam( 0, x ) || !exec.getParam( 1, y ) || !exec.getParam( 2, flags ) )
635  {
636  return new BError( "Invalid parameter type" );
637  }
638 
639  if ( !npc.realm->valid( x, y, npc.z ) )
640  return new BError( "Invalid Coordinates for Realm" );
641  Core::UFACING fac = direction_toward( &npc, x, y );
642  if ( npc.facing == fac )
643  return new BLong( 0 ); // nothing to do here
644 
645  if ( !npc.face( fac, flags ) )
646  return new BLong( 0 ); // I couldn't move!
647 
649  return new BLong( 1 );
650 }
651 
653 {
654  Core::xcoord x;
655  Core::ycoord y;
656  int flags;
657 
658  if ( !exec.getParam( 0, x ) || !exec.getParam( 1, y ) || !exec.getParam( 2, flags ) )
659  {
660  return new BError( "Invalid parameter type" );
661  }
662 
663  if ( !npc.realm->valid( x, y, npc.z ) )
664  return new BError( "Invalid Coordinates for Realm" );
665  Core::UFACING fac = direction_away( &npc, x, y );
666  if ( npc.facing == fac )
667  return new BLong( 0 ); // nothing to do here
668 
669  if ( !npc.face( fac, flags ) )
670  return new BLong( 0 ); // I couldn't move!
671 
673  return new BLong( 1 );
674 }
675 
676 
678 {
679  if ( npc.squelched() )
680  return new BError( "NPC is squelched" );
681  else if ( npc.hidden() )
682  npc.unhide();
683 
684  const char* text = exec.paramAsString( 0 );
685  std::string texttype_str = Clib::strlower( exec.paramAsString( 1 ) );
686  int doevent;
687  exec.getParam( 2, doevent );
688  u8 texttype;
689  if ( texttype_str == "default" )
690  texttype = Core::TEXTTYPE_NORMAL;
691  else if ( texttype_str == "whisper" )
692  texttype = Core::TEXTTYPE_WHISPER;
693  else if ( texttype_str == "yell" )
694  texttype = Core::TEXTTYPE_YELL;
695  else
696  return new BError( "texttype string param must be either 'default', 'whisper', or 'yell'" );
697 
698 
700  msg->offset += 2;
701  msg->Write<u32>( npc.serial_ext );
702  msg->WriteFlipped<u16>( npc.graphic );
703  msg->Write<u8>( texttype );
704  msg->WriteFlipped<u16>( npc.speech_color() );
705  msg->WriteFlipped<u16>( npc.speech_font() );
706  msg->Write( npc.name().c_str(), 30 );
707  msg->Write( text, ( strlen( text ) > SPEECH_MAX_LEN + 1 )
708  ? SPEECH_MAX_LEN + 1
709  : static_cast<u16>( strlen( text ) + 1 ) );
710  u16 len = msg->offset;
711  msg->offset = 1;
712  msg->WriteFlipped<u16>( len );
713 
714  // send to those nearby
715  u16 range;
716  if ( texttype == Core::TEXTTYPE_WHISPER )
718  else if ( texttype == Core::TEXTTYPE_YELL )
720  else
723  [&]( Mobile::Character* chr ) {
724  if ( !chr->is_visible_to_me( &npc ) )
725  return;
726  msg.Send( chr->client, len );
727  } );
728 
729  if ( doevent >= 1 )
730  {
732  npc.x, npc.y, npc.realm, range, [&]( Mobile::Character* chr ) {
733  Mobile::NPC* othernpc = static_cast<Mobile::NPC*>( chr );
734  if ( chr != &npc )
735  othernpc->on_pc_spoke( &npc, text, texttype );
736  } );
737  }
738 
739  return nullptr;
740 }
741 
743 {
744  if ( npc.squelched() )
745  return new BError( "NPC is squelched" );
746  else if ( npc.hidden() )
747  npc.unhide();
748 
749  ObjArray* oText;
750  const String* lang;
751  int doevent;
752 
753  if ( getObjArrayParam( 0, oText ) && getStringParam( 2, lang ) && getParam( 3, doevent ) )
754  {
755  std::string texttype_str = Clib::strlower( exec.paramAsString( 1 ) );
756  if ( texttype_str != "default" && texttype_str != "whisper" && texttype_str != "yell" )
757  {
758  return new BError( "texttype string param must be either 'default', 'whisper', or 'yell'" );
759  }
760 
761  size_t textlenucc = oText->ref_arr.size();
762  if ( textlenucc > SPEECH_MAX_LEN )
763  return new BError( "Unicode array exceeds maximum size." );
764  if ( lang->length() != 3 )
765  return new BError( "langcode must be a 3-character code." );
766  if ( !Core::convertArrayToUC( oText, gwtext, textlenucc ) )
767  return new BError( "Invalid value in Unicode array." );
768 
769  std::string languc = Clib::strupper( lang->value() );
770  unsigned textlen = 0;
771 
772  // textlen = wcslen((const wchar_t*)wtext) + 1;
773  while ( gwtext[textlen] != L'\0' )
774  ++textlen;
775  if ( textlen > SPEECH_MAX_LEN )
776  textlen = SPEECH_MAX_LEN;
777 
778  u8 texttype;
779  if ( texttype_str == "whisper" )
780  texttype = Core::TEXTTYPE_WHISPER;
781  else if ( texttype_str == "yell" )
782  texttype = Core::TEXTTYPE_YELL;
783  else
784  texttype = Core::TEXTTYPE_NORMAL;
785 
787  talkmsg->offset += 2;
788  talkmsg->Write<u32>( npc.serial_ext );
789  talkmsg->WriteFlipped<u16>( npc.graphic );
790  talkmsg->Write<u8>( texttype );
791  talkmsg->WriteFlipped<u16>( npc.speech_color() );
792  talkmsg->WriteFlipped<u16>( npc.speech_font() );
793  talkmsg->Write( languc.c_str(), 4 );
794  talkmsg->Write( npc.description().c_str(), 30 );
795  talkmsg->WriteFlipped( &gwtext[0], static_cast<u16>( textlen ) );
796  u16 len = talkmsg->offset;
797  talkmsg->offset = 1;
798  talkmsg->WriteFlipped<u16>( len );
799 
800  u16 range;
801  if ( texttype == Core::TEXTTYPE_WHISPER )
803  else if ( texttype == Core::TEXTTYPE_YELL )
805  else
808  [&]( Mobile::Character* chr ) {
809  if ( !chr->is_visible_to_me( &npc ) )
810  return;
811  talkmsg.Send( chr->client, len );
812  } );
813 
814  if ( doevent >= 1 )
815  {
816  char ntextbuf[SPEECH_MAX_LEN + 1];
817  int ntextbuflen = 0;
818  for ( unsigned i = 0; i < textlen; ++i )
819  {
820  ntextbuf[ntextbuflen++] = std::wcout.narrow( (wchar_t)gwtext[i], '?' );
821  }
822  ntextbuf[ntextbuflen++] = 0;
824  npc.x, npc.y, npc.realm, range, [&]( Mobile::Character* chr ) {
825  Mobile::NPC* othernpc = static_cast<Mobile::NPC*>( chr );
826  if ( othernpc != &npc )
827  othernpc->on_pc_spoke( &npc, ntextbuf, texttype, gwtext, languc.c_str(), nullptr );
828  } );
829  }
830  }
831  else
832  {
833  return new BError( "A parameter was invalid" );
834  }
835  return nullptr;
836 }
837 
839 {
840  std::unique_ptr<BStruct> oa( new BStruct );
841 
842  oa->addMember( "x", new BLong( npc.x ) );
843  oa->addMember( "y", new BLong( npc.y ) );
844  oa->addMember( "z", new BLong( npc.z ) );
845 
846  return oa.release();
847 }
848 
850 {
851  return new String( Mobile::FacingStr( static_cast<Core::UFACING>( npc.facing ) ) );
852 }
853 
855 {
856  const String* propname_str;
857  if ( exec.getStringParam( 0, propname_str ) )
858  {
859  std::string val;
860  if ( npc.getprop( propname_str->value(), val ) )
861  {
862  return BObjectImp::unpack( val.c_str() );
863  }
864  else
865  {
866  return new BError( "Property not found" );
867  }
868  }
869  else
870  {
871  return new BError( "Invalid parameter type" );
872  }
873 }
874 
876 {
877  const String* propname_str;
878  if ( exec.getStringParam( 0, propname_str ) )
879  {
880  BObjectImp* propval = getParamImp( 1 );
881  npc.setprop( propname_str->value(), propval->pack() );
882  return new BLong( 1 );
883  }
884  else
885  {
886  return new BError( "Invalid parameter type" );
887  }
888 }
889 
891 {
892  // UNTESTED
894  {
896  i->realm = npc.realm;
897  std::unique_ptr<Items::Item> item( i );
898  item->layer = Core::LAYER_BACKPACK;
899  if ( npc.equippable( item.get() ) )
900  {
901  npc.equip( item.release() );
902  }
903  }
904  return new BLong( 1 );
905 }
906 
908 {
909  // UNTESTED
910  const BLong* objtype = exec.getLongParam( 0 );
911  if ( objtype == nullptr )
912  return new BLong( 0 );
913 
914  Core::UContainer* backpack = npc.backpack();
915  if ( backpack == nullptr )
916  return new BLong( 0 );
917 
918  Items::Item* i = Items::Item::create( static_cast<unsigned int>( objtype->value() ) );
919  i->realm = npc.realm;
920  std::unique_ptr<Items::Item> item( i );
921  if ( item.get() == nullptr )
922  return new BLong( 0 );
923 
924  if ( !backpack->can_add( *item ) )
925  return new BLong( 0 );
926 
927  u8 slotIndex = item->slot_index();
928  if ( !backpack->can_add_to_slot( slotIndex ) )
929  return new BLong( 0 );
930 
931  if ( !item->slot_index( slotIndex ) )
932  return new BLong( 0 );
933 
934  u32 serial = item->serial;
935 
936  backpack->add( item.release() );
937 
938  return new BLong( serial );
939 }
940 
942 {
943  String* arealist =
945  if ( arealist == nullptr )
946  return new String( "" );
947 
949  std::unique_ptr<BoundingBoxObjImp> bbox_owner( bbox );
950 
951  // const std::string& areas = arealist->value();
952 
953  ISTRINGSTREAM is( arealist->value() );
954 
955  Mobile::Area a;
956  // FIXME this is a terrible data format.
957  while ( is >> a.topleft.x >> a.topleft.y >> a.bottomright.x >> a.bottomright.y )
958  {
959  ( *bbox )->addarea( a );
960  }
961 
962  return bbox_owner.release();
963 }
964 
966 {
967  Mobile::Character* chr;
968  if ( getCharacterParam( exec, 0, chr ) && chr != &npc )
969  {
970  npc.set_opponent( chr );
971  return new BLong( 1 );
972  }
973  else
974  {
975  npc.set_opponent( nullptr );
976  return new BLong( 0 );
977  }
978 }
979 
981 {
982  int warmode;
983  if ( exec.getParam( 0, warmode ) )
984  {
985  npc.set_warmode( warmode != 0 );
986  return new BLong( 1 );
987  }
988  else
989  {
990  return new BLong( 0 );
991  }
992 }
993 }
994 }
unsigned char u8
Definition: rawtypes.h:25
Bscript::BObjectImp * mf_RunTowardLocation()
Definition: npcmod.cpp:576
Bscript::BObjectImp * say()
Definition: npcmod.cpp:677
Bscript::BObjectImp * mf_SetOpponent()
Definition: npcmod.cpp:965
static Item * create(u32 objtype, u32 serial=0)
Definition: itemcr.cpp:53
bool can_add_to_slot(u8 &slotIndex)
Definition: containr.cpp:178
#define POL_OVERRIDE
const std::string & value() const
Definition: impstr.h:67
u16 gwtext[(SPEECH_MAX_LEN+1)]
Definition: unimod.cpp:140
Bscript::BObjectImp * face()
Definition: npcmod.cpp:311
BObjectType type() const
Definition: bobject.h:358
int value() const
Definition: bobject.h:592
void SleepFor(int secs)
Definition: osmod.cpp:824
const char * FacingStr(Core::UFACING facing)
Definition: ufacing.cpp:34
void set_opponent(Character *opponent, bool inform_old_opponent=true)
Definition: charactr.cpp:2994
virtual bool can_add(const Items::Item &item) const
Definition: containr.cpp:168
Bscript::BObjectImp * mf_WalkAwayFromLocation()
Definition: npcmod.cpp:594
bool isa(BObjectType type) const
Definition: bobject.h:353
void setprop(const std::string &propname, const std::string &propvalue)
Definition: uobject.cpp:160
Bscript::BObjectImp * mf_Self()
Definition: npcmod.cpp:181
unsigned short ycoord
Definition: poltype.h:20
virtual long contains(const BObjectImp &objimp) const
Definition: object.cpp:946
unsigned short whisper_range
Definition: ssopt.h:75
bool ismobile() const
Definition: baseobject.h:104
#define SPEECH_MAX_LEN
Definition: pktdef.h:27
bool getParam(unsigned param, int &value)
Definition: execmodl.cpp:62
Core::UFACING GetRandomFacing()
Definition: ufacing.cpp:28
unsigned short yell_range
Definition: ssopt.h:76
virtual void on_facing_changed() POL_OVERRIDE
Definition: charactr.cpp:1748
bool is_visible_to_me(const Character *chr) const
Definition: charactr.cpp:2658
Bscript::BObjectImp * mf_RunToward()
Definition: npcmod.cpp:445
bool _internal_move(Core::UFACING facing, int run)
Definition: npcmod.cpp:217
BObjectImp * getParamImp(unsigned param)
Definition: execmodl.cpp:22
const BLong * getLongParam(unsigned param)
Definition: executor.cpp:352
Core::UFACING direction_toward(const Character *src, const Core::UObject *idst)
Definition: ufacing.cpp:58
static void InRange(u16 x, u16 y, const Realms::Realm *realm, unsigned range, F &&f)
Definition: uworld.h:235
Bscript::BObjectImp * position()
Definition: npcmod.cpp:838
virtual u8 typeOfInt() const POL_OVERRIDE
Definition: npcmod.cpp:111
Bscript::BObjectImp * move()
Definition: npcmod.cpp:355
const char * paramAsString(unsigned param)
Definition: executor.cpp:209
virtual void add(Items::Item *item)
Definition: containr.cpp:194
Bscript::BObjectImp * facing()
Definition: npcmod.cpp:849
virtual std::string pack() const
Definition: object.cpp:201
#define EXPLICIT_CAST(totype, fromtype)
Definition: clib.h:24
Bscript::BObjectImp * CreateItem()
Definition: npcmod.cpp:907
virtual const char * typeOf() const POL_OVERRIDE
Definition: npcmod.cpp:110
const BApplicObjType * object_type() const
Definition: bobject.h:897
unsigned short u16
Definition: rawtypes.h:26
unsigned int u32
Definition: rawtypes.h:27
Bscript::BObjectImp * mf_RunAwayFrom()
Definition: npcmod.cpp:483
bool getCharacterParam(Bscript::Executor &exec, unsigned param, Mobile::Character *&chrptr)
Definition: uoexhelp.cpp:140
bool getprop(const std::string &propname, std::string &propvalue) const
Definition: uobject.cpp:155
Core::UOExecutor * ex
Definition: npc.h:250
Bscript::BObjectImp * CanMove()
Definition: npcmod.cpp:141
bool move(unsigned char dir)
Definition: charactr.cpp:3757
#define DEBUGLOG
Definition: logfacility.h:237
bool face(Core::UFACING i_facing, int flags=0)
Definition: charactr.cpp:3678
ExecutorModule * findModule(const std::string &name)
Definition: executor.cpp:3038
std::vector< BObjectRef > fparams
Definition: executor.h:133
int random_int(int i)
Definition: random.cpp:34
bool convertArrayToUC(Bscript::ObjArray *&in_text, u16 *out_wtext, size_t textlen, bool ConvToBE, bool nullterm)
Definition: unicode.cpp:21
BApplicObjType bounding_box_type
Definition: npcmod.cpp:100
bool enabled
Definition: npc.h:77
Bscript::BObjectImp * getproperty()
Definition: npcmod.cpp:854
Bscript::BObjectImp * mf_TurnAwayFromLocation()
Definition: npcmod.cpp:652
bool could_move(Core::UFACING dir) const
Definition: npc.cpp:174
Bscript::BObjectImp * mf_SetWarMode()
Definition: npcmod.cpp:980
void getpos_ifmove(Core::UFACING i_facing, unsigned short *px, unsigned short *py)
Definition: charactr.cpp:2770
bool use_adjustments() const
Definition: npc.cpp:1048
unsigned short y
Definition: npc.h:80
static BObjectImp * unpack(const char *pstr)
Definition: object.cpp:120
virtual BObjectImp * copy() const POL_OVERRIDE
Definition: npcmod.cpp:112
const std::string & scriptname() const
Definition: execmodl.cpp:107
#define UOBJ_BACKPACK
Definition: objtype.h:202
unsigned short speech_range
Definition: ssopt.h:74
Bscript::BObjectImp * CreateBackpack()
Definition: npcmod.cpp:890
const String * getStringParam(unsigned param)
Definition: execmodl.cpp:36
void equip(Items::Item *item)
Definition: charactr.cpp:1433
Bscript::BObjectImp * mf_Wander()
Definition: npcmod.cpp:285
SettingsManager settingsManager
Definition: settings.cpp:14
Bscript::BObjectImp * setproperty()
Definition: npcmod.cpp:875
Bscript::BObjectImp * mf_RunAwayFromLocation()
Definition: npcmod.cpp:611
#define PKTIN_02_FACING_MASK
Definition: pktdef.h:75
unsigned short dstart
Definition: npc.h:81
Core::UContainer * backpack() const
Definition: charactr.cpp:1276
std::array< int, 7 > adjustments
Definition: ufacing.cpp:24
Bscript::BObjectImp * mf_SetAnchor()
Definition: npcmod.cpp:186
#define ISTRINGSTREAM
Definition: stlutil.h:73
bool getUObjectParam(Executor &exec, unsigned param, UObject *&objptr)
Definition: uoexhelp.cpp:369
Bscript::BObjectImp * mf_WalkTowardLocation()
Definition: npcmod.cpp:559
const String * getStringParam(unsigned param)
Definition: executor.cpp:347
std::string strlower(const std::string &str)
Definition: strutil.cpp:276
Realms::Realm * realm
Definition: baseobject.h:56
BoundingBoxObjImp(const Mobile::BoundingBox &b)
Definition: npcmod.cpp:106
Anchor anchor
Definition: npc.h:240
bool anchor_allows_move(Core::UFACING dir) const
Definition: npc.cpp:150
void set_warmode(bool warmode)
Definition: charactr.cpp:3072
Core::UFACING direction_away(const Character *src, const Core::UObject *idst)
Definition: ufacing.cpp:153
OSExecutorModule * os_module
Definition: npcmod.h:54
Bscript::BObjectImp * mf_WalkToward()
Definition: npcmod.cpp:424
Bscript::BObjectImp * mf_TurnTowardLocation()
Definition: npcmod.cpp:628
bool getObjArrayParam(unsigned param, ObjArray *&pobjarr)
Definition: execmodl.cpp:57
unsigned short psub
Definition: npc.h:82
Bscript::BObjectImp * IsLegalMove()
Definition: npcmod.cpp:116
Bscript::BObjectImp * mf_TurnAwayFrom()
Definition: npcmod.cpp:530
unsigned short run_speed
Definition: npc.h:237
bool valid(unsigned short x, unsigned short y, short z) const
Definition: realm.cpp:119
bool run(int argc, char **argv)
std::string strupper(const std::string &str)
Definition: strutil.cpp:281
NPCExecutorModule(Bscript::Executor &ex, Mobile::NPC &npc)
Definition: npcmod.cpp:86
bool equippable(const Items::Item *item) const
Definition: charactr.cpp:1356
virtual std::string description() const
Definition: uobject.cpp:201
virtual std::string name() const
Definition: uobject.cpp:196
bool squelched() const
Definition: charactr.cpp:4042
Bscript::BObjectImp * mf_TurnToward()
Definition: npcmod.cpp:502
Bscript::BObjectImp * mf_WalkAwayFrom()
Definition: npcmod.cpp:464
Bscript::BObjectImp * SayUC()
Definition: npcmod.cpp:742
bool layer_is_equipped(int layer) const
Definition: charactr.cpp:1337
Definition: berror.cpp:12
bool DecodeFacing(const char *dir, Core::UFACING &facing)
Definition: ufacing.cpp:167
size_t length() const
Definition: impstr.h:68
static const char * typestr(BObjectType typ)
Definition: object.cpp:218
Bscript::BObjectImp * move_self(Core::UFACING facing, bool run, bool adjust_ok=false)
Definition: npcmod.cpp:240
unsigned short x
Definition: npc.h:79
unsigned short xcoord
Definition: poltype.h:19
bool hidden() const
Definition: charactr.h:941
BObjectImp * getParamImp(unsigned param)
Definition: executor.cpp:266
void SleepForMs(int msecs)
Definition: osmod.cpp:834
bool getParam(unsigned param, int &value)
Definition: executor.cpp:363
Bscript::BObjectImp * makeboundingbox()
Definition: npcmod.cpp:941