Pol  Revision:cb584c9
uomod2.cpp
Go to the documentation of this file.
1 
29 /*
30  UOEMOD2.CPP - a nice place for the Buy/Sell Interface Functions
31  */
32 
33 #include "pol_global_config.h"
34 
35 #include <ctype.h>
36 #include <stddef.h>
37 #include <string>
38 
39 #include "../../bscript/berror.h"
40 #include "../../bscript/bobject.h"
41 #include "../../bscript/bstruct.h"
42 #include "../../bscript/eprog.h"
43 #include "../../bscript/executor.h"
44 #include "../../bscript/impstr.h"
45 #include "../../clib/Program/ProgramConfig.h"
46 #include "../../clib/clib.h"
47 #include "../../clib/clib_endian.h"
48 #include "../../clib/compilerspecifics.h"
49 #include "../../clib/logfacility.h"
50 #include "../../clib/make_unique.hpp"
51 #include "../../clib/passert.h"
52 #include "../../clib/rawtypes.h"
53 #include "../../clib/refptr.h"
54 #include "../../plib/pkg.h"
55 #include "../../plib/staticblock.h"
56 #include "../../plib/systemstate.h"
57 #include "../accounts/account.h"
58 #include "../accounts/accounts.h"
59 #include "../accounts/acscrobj.h"
60 #include "../containr.h"
61 #include "../core.h"
62 #include "../exscrobj.h"
63 #include "../globals/memoryusage.h"
64 #include "../globals/script_internals.h"
65 #include "../globals/state.h"
66 #include "../globals/uvars.h"
67 #include "../item/item.h"
68 #include "../item/itemdesc.h"
69 #include "../layers.h"
70 #include "../mobile/charactr.h"
71 #include "../mobile/npc.h"
72 #include "../multi/customhouses.h"
73 #include "../multi/house.h"
74 #include "../multi/multi.h"
75 #include "../multi/multidef.h"
76 #include "../network/cgdata.h"
77 #include "../network/client.h"
78 #include "../network/packethelper.h"
79 #include "../network/packetinterface.h"
80 #include "../network/packets.h"
81 #include "../objtype.h"
82 #include "../pktboth.h"
83 #include "../pktdef.h"
84 #include "../pktin.h"
85 #include "../polclass.h"
86 #include "../profile.h"
87 #include "../realms/realm.h"
88 #include "../reftypes.h"
89 #include "../scrstore.h"
90 #include "../sngclick.h"
91 #include "../statmsg.h"
92 #include "../tooltips.h"
93 #include "../uconst.h"
94 #include "../ufunc.h"
95 #include "../uobject.h"
96 #include "../uoexec.h"
97 #include "../uoscrobj.h"
98 #include "../uworld.h"
99 #include "osmod.h"
100 #include "uomod.h"
101 
102 #ifdef MEMORYLEAK
103 #include "../../clib/opnew.h"
104 #endif
105 
106 
107 #ifdef USE_SYSTEM_ZLIB
108 #include <zlib.h>
109 #else
110 #include "../../../lib/zlib/zlib.h"
111 #endif
112 
113 namespace Pol
114 {
115 namespace Core
116 {
117 bool validhair( u16 HairStyle );
118 bool validbeard( u16 BeardStyle );
119 } // namespace Core
120 namespace Module
121 {
122 using namespace Bscript;
123 using namespace Network;
124 using namespace Mobile;
125 using namespace Items;
126 using namespace Core;
127 
128 #define CONST_DEFAULT_ZRANGE 19
129 
130 /*
131 0000: 74 02 70 40 29 ca d8 28 00 00 00 03 0b 53 65 77 t.p@)..( .....Sew
132 0010: 69 6e 67 20 6b 69 74 00 00 00 00 0d 09 53 63 69 ing kit. .....Sci
133 0020: 73 73 6f 72 73 00 00 00 00 09 0a 44 79 69 6e 67 ssors... ...Dying
134 0030: 20 74 75 62 00 00 00 00 09 05 44 79 65 73 00 00 tub.... ..Dyes..
135 0040: 00 00 1b 08 44 6f 75 62 6c 65 74 00 00 00 00 1a ....Doub let.....
136 0050: 0c 53 68 6f 72 74 20 70 61 6e 74 73 00 00 00 00 .Short p ants....
137 0060: 37 0c 46 61 6e 63 79 20 73 68 69 72 74 00 00 00 7.Fancy shirt...
138 0070: 00 26 0b 4c 6f 6e 67 20 70 61 6e 74 73 00 00 00 .&.Long pants...
139 0080: 00 19 0c 46 61 6e 63 79 20 64 72 65 73 73 00 00 ...Fancy dress..
140 0090: 00 00 39 0c 50 6c 61 69 6e 20 64 72 65 73 73 00 ..9.Plai n dress.
141 00a0: 00 00 00 21 06 53 6b 69 72 74 00 00 00 00 1f 05 ...!.Ski rt......
142 00b0: 4b 69 6c 74 00 00 00 00 1a 0b 48 61 6c 66 20 61 Kilt.... ..Half a
143 00c0: 70 72 6f 6e 00 00 00 00 49 05 52 6f 62 65 00 00 pron.... I.Robe..
144 00d0: 00 00 32 06 43 6c 6f 61 6b 00 00 00 00 32 06 43 ..2.Cloa k....2.C
145 00e0: 6c 6f 61 6b 00 00 00 00 1b 08 44 6f 75 62 6c 65 loak.... ..Double
146 00f0: 74 00 00 00 00 21 06 54 75 6e 69 63 00 00 00 00 t....!.T unic....
147 0100: 39 0c 4a 65 73 74 65 72 20 73 75 69 74 00 00 00 9.Jester suit...
148 0110: 00 1f 0b 4a 65 73 74 65 72 20 68 61 74 00 00 00 ...Jeste r hat...
149 0120: 00 19 0b 46 6c 6f 70 70 79 20 68 61 74 00 00 00 ...Flopp y hat...
150 0130: 00 1a 0e 57 69 64 65 2d 62 72 69 6d 20 68 61 74 ...Wide- brim hat
151 0140: 00 00 00 00 1b 04 43 61 70 00 00 00 00 1a 0f 54 ......Ca p......T
152 0150: 61 6c 6c 20 73 74 72 61 77 20 68 61 74 00 00 00 all stra w hat...
153 0160: 00 19 0a 53 74 72 61 77 20 68 61 74 00 00 00 00 ...Straw hat....
154 0170: 1e 0d 57 69 7a 61 72 64 27 73 20 68 61 74 00 00 ..Wizard 's hat..
155 0180: 00 00 1a 07 42 6f 6e 6e 65 74 00 00 00 00 1b 0e ....Bonn et......
156 0190: 46 65 61 74 68 65 72 65 64 20 68 61 74 00 00 00 Feathere d hat...
157 01a0: 00 1a 0d 54 72 69 63 6f 72 6e 65 20 68 61 74 00 ...Trico rne hat.
158 01b0: 00 00 00 0e 08 42 61 6e 64 61 6e 61 00 00 00 00 .....Ban dana....
159 01c0: 0d 09 53 6b 75 6c 6c 63 61 70 00 00 00 00 02 0d ..Skullc ap......
160 01d0: 46 6f 6c 64 65 64 20 63 6c 6f 74 68 00 00 00 00 Folded c loth....
161 01e0: 02 0d 46 6f 6c 64 65 64 20 63 6c 6f 74 68 00 00 ..Folded cloth..
162 01f0: 00 00 02 0d 46 6f 6c 64 65 64 20 63 6c 6f 74 68 ....Fold ed cloth
163 0200: 00 00 00 00 02 0d 46 6f 6c 64 65 64 20 63 6c 6f ......Fo lded clo
164 0210: 74 68 00 00 00 00 4a 0e 42 6f 6c 74 20 6f 66 20 th....J. Bolt of
165 0220: 63 6c 6f 74 68 00 00 00 00 4a 0e 42 6f 6c 74 20 cloth... .J.Bolt
166 0230: 6f 66 20 63 6c 6f 74 68 00 00 00 00 5b 0f 42 61 of cloth ....[.Ba
167 0240: 6c 65 20 6f 66 20 63 6f 74 74 6f 6e 00 00 00 00 le of co tton....
168 0250: 2d 0d 50 69 6c 65 20 6f 66 20 77 6f 6f 6c 00 00 -.Pile o f wool..
169 0260: 00 00 61 0c 46 6c 61 78 20 62 75 6e 64 6c 65 00 ..a.Flax bundle.
170 */
171 // msg 3C: be sure to not send the whole structure, just as many 'items' as you insert
172 
173 bool send_vendorwindow_contents( Client* client, UContainer* for_sale, bool send_aos_tooltip )
174 {
176  msg->offset += 2; // msglen
177  msg->Write<u32>( for_sale->serial_ext );
178  msg->offset++; // num_items
179  u8 num_items = 0;
180  // FIXME: ick! apparently we need to iterate backwards... WTF?
181  for ( int i = for_sale->count() - 1; i >= 0; --i )
182  {
183  Item* item = ( *for_sale )[i];
184  // const ItemDesc& id = find_itemdesc( item->objtype_ );
185  std::string desc = item->merchant_description();
186  size_t addlen = 5 + desc.size();
187  if ( msg->offset + addlen > sizeof msg->buffer )
188  {
189  return false;
190  }
191  msg->WriteFlipped<u32>( item->sellprice() );
192  msg->Write<u8>( desc.size() + 1 ); // Don't forget the nullptr
193  msg->Write( desc.c_str(), static_cast<u16>( desc.size() + 1 ) );
194  ++num_items;
195 
196  if ( send_aos_tooltip )
197  SendAOSTooltip( client, item, true );
198  }
199  u16 len = msg->offset;
200  msg->offset = 1;
201  msg->WriteFlipped<u16>( len );
202  msg->offset += 4;
203  msg->Write<u8>( num_items );
204  msg.Send( client, len );
205  return true;
206 }
207 
208 BObjectImp* UOExecutorModule::mf_SendBuyWindow( /* character, container, vendor, items, flags */ )
209 {
210  Character *chr, *mrchnt;
211  Item *item, *item2;
212  NPC* merchant;
213  int flags;
214  UContainer *for_sale, *bought;
215  unsigned char save_layer_one, save_layer_two;
216 
217  if ( getCharacterParam( exec, 0, chr ) && getItemParam( exec, 1, item ) &&
218  getCharacterParam( exec, 2, mrchnt ) && getItemParam( exec, 3, item2 ) &&
219  getParam( 4, flags ) )
220  {
221  if ( !chr->has_active_client() )
222  {
223  return new BError( "No client connected to character" );
224  }
225 
226  if ( item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
227  {
228  for_sale = static_cast<UContainer*>( item );
229  }
230  else
231  {
232  return new BError( "Parameter 1 invalid" );
233  }
234 
235  if ( mrchnt->isa( UOBJ_CLASS::CLASS_NPC ) )
236  {
237  merchant = static_cast<NPC*>( mrchnt );
238  }
239  else
240  {
241  return new BError( "Parameter 2 invalid" );
242  }
243 
244  if ( item2->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
245  {
246  bought = static_cast<UContainer*>( item2 );
247  }
248  else
249  {
250  return new BError( "Parameter 3 invalid" );
251  }
252 
253  // say_above(merchant, "How may I help you?" );
254  }
255  else
256  {
257  return new BError( "A parameter was invalid" );
258  }
259 
260 
261  // try this
262  save_layer_one = for_sale->layer;
263  for_sale->layer = LAYER_VENDOR_FOR_SALE;
264  send_wornitem( chr->client, merchant, for_sale );
265  for_sale->layer = save_layer_one;
266  for_sale->x = merchant->x;
267  for_sale->y = merchant->y;
268  for_sale->z = merchant->z;
269  // chr->add_additional_legal_item( for_sale );
270 
271  save_layer_two = bought->layer;
273  send_wornitem( chr->client, merchant, bought );
274  bought->layer = save_layer_two;
275  bought->x = merchant->x;
276  bought->y = merchant->y;
277  bought->z = merchant->z;
278  // chr->add_additional_legal_item( bought );
279 
280  bool send_aos_tooltip = flags & VENDOR_SEND_AOS_TOOLTIP ? true : false;
281 
282  chr->client->gd->vendor.set( merchant );
283  chr->client->gd->vendor_for_sale.set( for_sale );
284  chr->client->gd->vendor_bought.set( bought );
285 
286  chr->client->pause(); /* Prevent lag time between messages */
287 
288  // Send the 'for sale' container
289  send_container_contents( chr->client, *for_sale );
290 
291  if ( !send_vendorwindow_contents( chr->client, for_sale, send_aos_tooltip ) )
292  {
293  chr->client->restart();
294  return new BError( "Too much crap in vendor's inventory!" );
295  }
296 
297  // Send the 'bought' container (?) (hmm, I think this is the player-sold items)
298  send_container_contents( chr->client, *bought );
299 
300  if ( !send_vendorwindow_contents( chr->client, bought, send_aos_tooltip ) )
301  {
302  chr->client->restart();
303  return new BError( "Too much crap in vendor's inventory!" );
304  }
305 
306  // This looks good
308  open_window->Write<u32>( merchant->serial_ext );
309  open_window->WriteFlipped<u16>( 0x0030u ); // FIXME: Serial of buy gump needs #define or enum?
310  if ( chr->client->ClientType & CLIENTTYPE_7090 )
311  open_window->WriteFlipped<u16>( 0x00u );
312  open_window.Send( chr->client );
313 
314  // Tell the client how much gold the character has, I guess
315  send_full_statmsg( chr->client, chr );
316 
317  chr->client->restart();
318 
319  return new BLong( 1 );
320 }
321 
322 
323 void send_clear_vendorwindow( Client* client, Character* vendor )
324 {
326  msg->WriteFlipped<u16>( sizeof msg->buffer );
327  msg->Write<u32>( vendor->serial_ext );
328  msg->Write<u8>( PKTBI_3B::STATUS_NOTHING_BOUGHT );
329  msg.Send( client );
330 }
331 unsigned int calculate_cost( Character* /*vendor*/, UContainer* for_sale, UContainer* bought,
332  PKTBI_3B* msg )
333 {
334  unsigned int amt = 0;
335 
336  int nitems = ( cfBEu16( msg->msglen ) - offsetof( PKTBI_3B, items ) ) / sizeof msg->items[0];
337 
338  for ( int i = 0; i < nitems; ++i )
339  {
340  u32 serial = cfBEu32( msg->items[i].item_serial );
341  Item* item = for_sale->find( serial );
342  if ( item == nullptr )
343  {
344  item = bought->find( serial );
345  if ( item == nullptr )
346  continue;
347  }
348  // const ItemDesc& id = find_itemdesc(item->objtype_);
349  amt += cfBEu16( msg->items[i].number_bought ) * item->sellprice();
350  }
351  return amt;
352 }
353 
354 void oldBuyHandler( Client* client, PKTBI_3B* msg )
355 {
356  // Close the gump
357 
359  return;
360 
361  UContainer* backpack = client->chr->backpack();
362  if ( backpack == nullptr )
363  return;
364 
365  NPC* vendor = client->gd->vendor.get();
366 
367  if ( vendor == nullptr || vendor->orphan() || vendor->serial_ext != msg->vendor_serial )
368  {
369  return;
370  }
371  client->gd->vendor.clear();
372 
373  UContainer* for_sale = client->gd->vendor_for_sale.get();
374  if ( for_sale == nullptr || for_sale->orphan() )
375  {
376  return;
377  }
378  client->gd->vendor_for_sale.clear();
379 
380  UContainer* vendor_bought = client->gd->vendor_bought.get();
381  if ( vendor_bought == nullptr || vendor_bought->orphan() )
382  {
383  return;
384  }
385  client->gd->vendor_bought.clear();
386 
387  unsigned int total_cost = calculate_cost( vendor, for_sale, vendor_bought, msg );
388  if ( total_cost > client->chr->gold_carried() )
389  {
390  send_clear_vendorwindow( client, vendor );
391  return;
392  }
393 
394  unsigned int amount_spent = 0;
395 
396  // buy each item individually
397  // note, we know the buyer can afford it all.
398  // the question is, can it all fit in his backpack?
399  int nitems = ( cfBEu16( msg->msglen ) - offsetof( PKTBI_3B, items ) ) / sizeof msg->items[0];
400 
401  bool from_bought;
402  for ( int i = 0; i < nitems; ++i )
403  {
404  from_bought = false;
405  u32 serial = cfBEu32( msg->items[i].item_serial );
406  Item* fs_item = for_sale->find( serial );
407  if ( fs_item == nullptr )
408  {
409  fs_item = vendor_bought->find( serial );
410  if ( fs_item == nullptr )
411  continue;
412  from_bought = true;
413  }
414  unsigned short numleft = cfBEu16( msg->items[i].number_bought );
415  if ( numleft > fs_item->getamount() )
416  numleft = fs_item->getamount();
417 
418  // const ItemDesc& id = find_itemdesc( fs_item->objtype_ );
419  while ( numleft )
420  {
421  unsigned short num;
422  if ( fs_item == nullptr )
423  break;
424  if ( fs_item->stackable() )
425  {
426  num = numleft;
427  }
428  else
429  {
430  num = 1;
431  }
432  Item* tobuy = nullptr;
433  if ( fs_item->amount_to_remove_is_partial( num ) )
434  {
435  tobuy = fs_item->remove_part_of_stack( num );
436  }
437  else
438  {
439  if ( from_bought )
440  vendor_bought->remove( fs_item );
441  else
442  for_sale->remove( fs_item );
443  tobuy = fs_item;
444  fs_item = nullptr;
445  }
446 
447  // move the whole item
448  ItemRef itemref(
449  tobuy ); // dave 1/28/3 prevent item from being destroyed before function ends
450  Item* existing_stack;
451  if ( tobuy->stackable() &&
452  ( existing_stack = backpack->find_addable_stack( tobuy ) ) != nullptr )
453  {
454  // dave 1-14-3 check backpack's insert scripts before moving.
456  existing_stack, tobuy->getamount(), tobuy ) )
457  {
458  if ( tobuy->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
459  {
460  continue;
461  }
462  }
463  else // put the item back just as if the pack had too many/too heavy items.
464  {
465  numleft = 0;
466  if ( fs_item )
467  fs_item->add_to_self( tobuy );
468  else
469  // FIXME : Add Grid Index Default Location Checks here.
470  // Remember, if index fails, move to the ground.
471  if ( from_bought )
472  vendor_bought->add( tobuy );
473  else
474  for_sale->add( tobuy );
475  continue;
476  }
477  numleft -= num;
478  amount_spent += tobuy->sellprice() * num;
479  u16 amtadded = tobuy->getamount();
480  existing_stack->add_to_self( tobuy );
481  update_item_to_inrange( existing_stack );
482 
483  backpack->on_insert_increase_stack( client->chr, UContainer::MT_CORE_MOVED, existing_stack,
484  amtadded );
485  }
486  else if ( backpack->can_add( *tobuy ) )
487  {
488  numleft -= num;
489 
490  // dave 12-20 check backpack's insert scripts before moving.
491  bool canInsert =
492  backpack->can_insert_add_item( client->chr, UContainer::MT_CORE_MOVED, tobuy );
493  if ( tobuy->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
494  {
495  continue;
496  }
497 
498  if ( !canInsert ) // put the item back just as if the pack had too many/too heavy items.
499  {
500  numleft = 0;
501  if ( fs_item )
502  fs_item->add_to_self( tobuy );
503  else
504  // FIXME : Add Grid Index Default Location Checks here.
505  // Remember, if index fails, move to the ground.
506  if ( from_bought )
507  vendor_bought->add( tobuy );
508  else
509  for_sale->add( tobuy );
510  continue;
511  }
512 
513  // FIXME : Add Grid Index Default Location Checks here.
514  // Remember, if index fails, move to the ground.
515  backpack->add_at_random_location( tobuy );
516  update_item_to_inrange( tobuy );
517  amount_spent += tobuy->sellprice() * num;
518 
519  backpack->on_insert_add_item( client->chr, UContainer::MT_CORE_MOVED, tobuy );
520  }
521  else
522  {
523  numleft = 0;
524  if ( fs_item )
525  fs_item->add_to_self( tobuy );
526  else
527  {
528  // FIXME : Add Grid Index Default Location Checks here.
529  // Remember, if index fails, move to the ground.
530  if ( from_bought )
531  vendor_bought->add( tobuy );
532  else
533  for_sale->add( tobuy );
534  }
535  }
536  }
537  }
538 
539  client->chr->spend_gold( amount_spent );
540 
541  std::unique_ptr<SourcedEvent> sale_event( new SourcedEvent( EVID_MERCHANT_SOLD, client->chr ) );
542  sale_event->addMember( "amount", new BLong( amount_spent ) );
543  vendor->send_event( sale_event.release() );
544 
545  send_clear_vendorwindow( client, vendor );
546 }
547 
548 void buyhandler( Client* client, PKTBI_3B* msg )
549 {
551  {
552  oldBuyHandler( client, msg );
553  return;
554  }
555  // Close the gump
556 
558  return;
559 
560  UContainer* backpack = client->chr->backpack();
561  if ( backpack == nullptr )
562  {
563  return;
564  }
565 
566  NPC* vendor = client->gd->vendor.get();
567  if ( vendor == nullptr || vendor->orphan() || vendor->serial_ext != msg->vendor_serial )
568  {
569  return;
570  }
571  client->gd->vendor.clear();
572 
573  UContainer* for_sale = client->gd->vendor_for_sale.get();
574  if ( for_sale == nullptr || for_sale->orphan() )
575  {
576  return;
577  }
578  client->gd->vendor_for_sale.clear();
579  UContainer* vendor_bought = client->gd->vendor_bought.get();
580  if ( vendor_bought == nullptr || vendor_bought->orphan() )
581  {
582  return;
583  }
584  client->gd->vendor_bought.clear();
585 
586  // buy each item individually
587  // the question is, can it all fit in his backpack?
588  // But who cares ... let the scripter(s) handle it!
589  int nitems = ( cfBEu16( msg->msglen ) - offsetof( PKTBI_3B, items ) ) / sizeof msg->items[0];
590 
591  std::unique_ptr<ObjArray> items_bought( new ObjArray );
592  for ( int i = 0; i < nitems; ++i )
593  {
594  Item* fs_item = for_sale->find( cfBEu32( msg->items[i].item_serial ) );
595  if ( fs_item == nullptr )
596  {
597  fs_item = vendor_bought->find( cfBEu32( msg->items[i].item_serial ) );
598  if ( fs_item == nullptr )
599  continue;
600  }
601  unsigned short numleft = cfBEu16( msg->items[i].number_bought );
602 
603  if ( numleft > fs_item->getamount() )
604  numleft = fs_item->getamount();
605 
606  std::unique_ptr<BStruct> entry( new BStruct );
607  entry->addMember( "item", fs_item->make_ref() );
608  entry->addMember( "amount", new BLong( numleft ) );
609 
610  items_bought->addElement( entry.release() );
611  }
612 
613  std::unique_ptr<SourcedEvent> sale_event( new SourcedEvent( EVID_MERCHANT_SOLD, client->chr ) );
614  sale_event->addMember( "shoppinglist", items_bought.release() );
615  vendor->send_event( sale_event.release() );
616 
617  send_clear_vendorwindow( client, vendor );
618 }
619 
620 bool send_vendorsell( Client* client, NPC* merchant, UContainer* sellfrom, UContainer* buyable,
621  bool send_aos_tooltip )
622 {
623  unsigned short num_items = 0;
625  msg->offset += 2;
626  msg->Write<u32>( merchant->serial_ext );
627  msg->offset += 2; // numitems
628 
629  UContainer::iterator buyable_itr, buyable_end;
630  if ( buyable != nullptr )
631  buyable_end = buyable->end();
632 
633  UContainer* cont = sellfrom;
634  while ( cont != nullptr )
635  {
636  for ( UContainer::iterator itr = cont->begin(), end = cont->end(); itr != end; ++itr )
637  {
638  Item* item = GET_ITEM_PTR( itr );
639  if ( item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
640  {
641  UContainer* cont2 = static_cast<UContainer*>( item );
642  if ( cont2->count() )
643  continue;
644  }
645  if ( item->newbie() )
646  continue;
647  unsigned int buyprice;
648  if ( !item->getbuyprice( buyprice ) )
649  continue;
650  std::string desc = item->merchant_description();
651  if ( msg->offset + desc.size() + 14 > sizeof msg->buffer )
652  {
653  return false;
654  }
655  if ( buyable != nullptr )
656  {
657  for ( buyable_itr = buyable->begin(); buyable_itr != buyable_end; ++buyable_itr )
658  {
659  Item* buyable_item = GET_ITEM_PTR( buyable_itr );
660  if ( buyable_item->objtype_ == item->objtype_ )
661  break;
662  }
663  if ( buyable_itr == buyable_end )
664  continue;
665  }
666 
667  msg->Write<u32>( item->serial_ext );
668  msg->WriteFlipped<u16>( item->graphic );
669  msg->WriteFlipped<u16>( item->color );
670  msg->WriteFlipped<u16>( item->getamount() );
671  msg->WriteFlipped<u16>( buyprice );
672  msg->WriteFlipped<u16>( desc.size() );
673  msg->Write( desc.c_str(), static_cast<u16>( desc.size() ), false ); // No null term
674  ++num_items;
675 
676  if ( send_aos_tooltip )
677  SendAOSTooltip( client, item, true );
678  }
679 
680  cont = nullptr;
681  }
682  u16 len = msg->offset;
683  msg->offset = 1;
684  msg->WriteFlipped<u16>( len );
685  msg->offset += 4;
686  msg->WriteFlipped<u16>( num_items );
687  msg.Send( client, len );
688  return true;
689 }
690 
691 BObjectImp* UOExecutorModule::mf_SendSellWindow( /* character, vendor, i1, i2, i3, flags */ )
692 {
693  Character *chr, *mrchnt;
694  NPC* merchant;
695  Item* wi1a;
696  Item* wi1b;
697  Item* wi1c;
698  int flags;
699  UContainer* merchant_bought;
700  UContainer* merchant_buyable = nullptr;
701 
702  if ( !( getCharacterParam( exec, 0, chr ) && getCharacterParam( exec, 1, mrchnt ) &&
703  getItemParam( exec, 2, wi1a ) && getItemParam( exec, 3, wi1b ) &&
704  getItemParam( exec, 4, wi1c ) && getParam( 5, flags ) ) )
705  {
706  return new BError( "A parameter was invalid" );
707  }
708 
709  if ( !chr->has_active_client() )
710  {
711  return new BError( "No client connected to character" );
712  }
713 
714  if ( mrchnt->isa( UOBJ_CLASS::CLASS_NPC ) )
715  {
716  merchant = static_cast<NPC*>( mrchnt );
717  }
718  else
719  {
720  return new BError( "Parameter 1 invalid" );
721  }
722  if ( wi1b->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
723  {
724  merchant_bought = static_cast<UContainer*>( wi1b );
725  }
726  else
727  {
728  return new BError( "Parameter 2 must be a container" );
729  }
730 
731  if ( flags & VENDOR_BUYABLE_CONTAINER_FILTER )
732  {
733  if ( wi1c->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
734  {
735  merchant_buyable = static_cast<UContainer*>( wi1c );
736  }
737  else
738  {
739  return new BError( "Parameter 3 must be a container" );
740  }
741  }
742 
743  if ( chr->backpack() == nullptr )
744  {
745  return new BError( "Character has no backpack" );
746  }
747 
748  unsigned char save_layer = wi1a->layer;
750  send_wornitem( chr->client, merchant, wi1a );
751  wi1a->layer = save_layer;
752 
753  save_layer = wi1b->layer;
755  send_wornitem( chr->client, merchant, wi1b );
756  wi1b->layer = save_layer;
757 
758  save_layer = wi1c->layer;
760  send_wornitem( chr->client, merchant, wi1c );
761  wi1c->layer = save_layer;
762 
763  bool send_aos_tooltip = flags & VENDOR_SEND_AOS_TOOLTIP ? true : false;
764 
765  send_vendorsell( chr->client, merchant, chr->backpack(), merchant_buyable, send_aos_tooltip );
766 
767  chr->client->gd->vendor.set( merchant );
768  chr->client->gd->vendor_bought.set( merchant_bought );
769 
770  return new BLong( 1 );
771 }
772 
773 extern BObjectImp* _create_item_in_container( UContainer* cont, const ItemDesc* descriptor,
774  unsigned short amount, bool force_stacking,
775  UOExecutorModule* uoemod );
776 // player selling to vendor
777 void oldSellHandler( Client* client, PKTIN_9F* msg )
778 {
779  UContainer* backpack = client->chr->backpack();
780  if ( backpack == nullptr )
781  return;
782 
783  NPC* vendor = client->gd->vendor.get();
784 
785  if ( vendor == nullptr || vendor->orphan() || vendor->serial_ext != msg->vendor_serial )
786  {
787  client->gd->vendor.clear();
788  client->gd->vendor_bought.clear();
789  return;
790  }
791 
792  UContainer* vendor_bought = client->gd->vendor_bought.get();
793  if ( vendor_bought == nullptr || vendor_bought->orphan() )
794  {
795  client->gd->vendor.clear();
796  client->gd->vendor_bought.clear();
797  return;
798  }
799 
800  unsigned int cost = 0;
801  int num_items = cfBEu16( msg->num_items );
802  Clib::sanitize_upperlimit( &num_items, ( 0xFFFF - 9 ) / 6 );
803 
804  for ( int i = 0; i < num_items; ++i )
805  {
806  u32 serial = cfBEu32( msg->items[i].serial );
807  u16 amount = cfBEu16( msg->items[i].amount );
808 
809  unsigned int buyprice;
810 
811  Item* item = backpack->find_toplevel( serial );
812  if ( item == nullptr )
813  return;
814  if ( item->newbie() )
815  continue;
816  if ( item->inuse() )
817  continue;
818  if ( !item->getbuyprice( buyprice ) )
819  continue;
820  if ( amount > item->getamount() )
821  amount = item->getamount();
822  Item* remainder_not_sold = nullptr;
823  if ( item->amount_to_remove_is_partial( amount ) )
824  remainder_not_sold = item->slice_stacked_item( amount );
825 
826  if ( vendor_bought->can_add( *item ) )
827  {
828  u16 tx, ty;
829  vendor_bought->get_random_location( &tx, &ty );
830  backpack->remove( item );
831  if ( remainder_not_sold != nullptr )
832  {
833  // FIXME : Add Grid Index Default Location Checks here.
834  // Remember, if index fails, move to the ground.
835  backpack->add( remainder_not_sold );
836  update_item_to_inrange( remainder_not_sold );
837  remainder_not_sold = nullptr;
838  }
839  item->x = tx;
840  item->y = ty;
841  item->z = 0;
842  // FIXME : Add Grid Index Default Location Checks here.
843  // Remember, if index fails, move to the ground.
844  vendor_bought->add( item );
845  update_item_to_inrange( item );
846  cost += buyprice * amount;
847  }
848 
849  if ( remainder_not_sold != nullptr )
850  {
851  item->add_to_self( remainder_not_sold );
852  update_item_to_inrange( item );
853  }
854  }
855 
856  // dave added 12-19. If no items are sold don't create any gold in the player's pack!
857  if ( cost > 0 )
858  {
859  // dave added 12-21, create stacks of 60k gold instead of one huge, invalid stack.
860  unsigned int temp_cost = cost;
861  while ( temp_cost > 60000 )
862  {
864  static_cast<unsigned short>( 60000 ), false,
865  nullptr ) );
866  temp_cost -= 60000;
867  }
868  if ( temp_cost > 0 )
869  {
871  static_cast<unsigned short>( temp_cost ), false,
872  nullptr ) );
873  }
874  }
875  std::unique_ptr<SourcedEvent> sale_event( new SourcedEvent( EVID_MERCHANT_BOUGHT, client->chr ) );
876  sale_event->addMember( "amount", new BLong( cost ) );
877  vendor->send_event( sale_event.release() );
878 
879  client->pause();
880 
881  send_full_statmsg( client, client->chr );
882 
883  send_clear_vendorwindow( client, vendor );
884 
885  client->gd->vendor_bought.clear();
886  client->gd->vendor.clear();
887  client->restart();
888 }
889 
890 void sellhandler( Client* client, PKTIN_9F* msg )
891 {
893  {
894  oldSellHandler( client, msg );
895  return;
896  }
897  UContainer* backpack = client->chr->backpack();
898  if ( backpack == nullptr )
899  return;
900 
901  NPC* vendor = client->gd->vendor.get();
902  if ( vendor == nullptr || vendor->orphan() || vendor->serial_ext != msg->vendor_serial )
903  {
904  client->gd->vendor.clear();
905  client->gd->vendor_bought.clear();
906  return;
907  }
908 
909  UContainer* vendor_bought = client->gd->vendor_bought.get();
910  if ( vendor_bought == nullptr || vendor_bought->orphan() )
911  {
912  client->gd->vendor.clear();
913  client->gd->vendor_bought.clear();
914  return;
915  }
916 
917  int num_items = cfBEu16( msg->num_items );
918  std::unique_ptr<ObjArray> items_sold( new ObjArray );
919  Clib::sanitize_upperlimit( &num_items, ( 0xFFFF - 9 ) / 6 );
920  for ( int i = 0; i < num_items; ++i )
921  {
922  u32 serial = cfBEu32( msg->items[i].serial );
923  u32 amount = cfBEu16( msg->items[i].amount );
924 
925  Item* item = backpack->find_toplevel( serial );
926 
927  if ( item == nullptr )
928  return;
929  if ( item->newbie() )
930  continue;
931  if ( item->inuse() )
932  continue;
933  if ( amount > item->getamount() )
934  amount = item->getamount();
935 
936  std::unique_ptr<BStruct> entry( new BStruct );
937  entry->addMember( "item", item->make_ref() );
938  entry->addMember( "amount", new BLong( amount ) );
939 
940  items_sold->addElement( entry.release() );
941  }
942  std::unique_ptr<SourcedEvent> sale_event( new SourcedEvent( EVID_MERCHANT_BOUGHT, client->chr ) );
943  sale_event->addMember( "shoppinglist", items_sold.release() );
944  vendor->send_event( sale_event.release() );
945 
946  send_clear_vendorwindow( client, vendor );
947  client->gd->vendor.clear();
948  client->gd->vendor_bought.clear();
949 }
950 
951 //
952 // "GUMP" Functions
953 //
955 {
956  /*
957  Client* client,
958  const char* layout,
959  const char* strings[]
960  */
961  int x, y, flags, gump_id;
962  Character* chr;
963  ObjArray* layout_arr;
964  ObjArray* data_arr;
965  if ( !( getCharacterParam( exec, 0, chr ) && exec.getObjArrayParam( 1, layout_arr ) &&
966  exec.getObjArrayParam( 2, data_arr ) && exec.getParam( 3, x ) && exec.getParam( 4, y ) &&
967  exec.getParam( 5, flags ) && exec.getParam( 6, gump_id ) ) )
968  {
969  return new BError( "Invalid parameter" );
970  }
971  if ( !chr->has_active_client() )
972  {
973  return new BError( "No client attached" );
974  }
975 
976  // Now determine the id to be assigned to the gump
977  u32 gumpid;
978  if ( gump_id )
979  {
980  // Validate and use the id requested by the script
981  if ( gump_id < 1 )
982  return new BError( "GumpID out of range" );
983  gumpid = (u32)gump_id;
984  if ( gumpid >= ScriptScheduler::PID_MIN )
985  return new BError( "GumpID out of range" );
986  }
987  else
988  {
989  // For keeping backward compatibility: we do not know how many scripts do rely
990  // on the fact that pid == gumpid when autogenerated
991  gumpid = this->uoexec.os_module->pid();
992  }
993 
994  /*
995  if (chr->client->gd->gump_uoemod != nullptr)
996  {
997  return new BError( "Client already has an active gump" );
998  }
999  */
1000  if ( ( chr->client->ClientType & CLIENTTYPE_UOSA ) || ( chr->client->IsUOKRClient() ) ||
1001  ( ( !( flags & SENDDIALOGMENU_FORCE_OLD ) ) &&
1002  ( chr->client->compareVersion( CLIENT_VER_5000 ) ) ) )
1003  return internal_SendCompressedGumpMenu( chr, layout_arr, data_arr, x, y, gumpid );
1004  else
1005  return internal_SendUnCompressedGumpMenu( chr, layout_arr, data_arr, x, y, gumpid );
1006 }
1007 
1008 
1010  ObjArray* layout_arr,
1011  ObjArray* data_arr, int x, int y,
1012  u32 gumpid )
1013 {
1015  msg->offset += 2;
1016  msg->Write<u32>( chr->serial_ext );
1017  msg->WriteFlipped<u32>( gumpid );
1018  msg->WriteFlipped<u32>( static_cast<u32>( x ) );
1019  msg->WriteFlipped<u32>( static_cast<u32>( y ) );
1020  u16 pos = msg->offset;
1021  msg->offset += 2; // layoutlen
1022  size_t layoutlen = 0;
1023  for ( unsigned i = 0; i < layout_arr->ref_arr.size(); ++i )
1024  {
1025  BObject* bo = layout_arr->ref_arr[i].get();
1026  if ( bo == nullptr )
1027  continue;
1028  BObjectImp* imp = bo->impptr();
1029  std::string s = imp->getStringRep();
1030 
1031  size_t addlen = 4 + s.length();
1032  layoutlen += addlen;
1033  if ( msg->offset + addlen > sizeof msg->buffer )
1034  {
1035  return new BError( "Buffer length exceeded" );
1036  }
1037  msg->Write( "{ ", 2, false );
1038  msg->Write( s.c_str(), static_cast<u16>( s.length() ), false );
1039  msg->Write( " }", 2, false );
1040  }
1041 
1042  if ( msg->offset + 1 > static_cast<int>( sizeof msg->buffer ) )
1043  {
1044  return new BError( "Buffer length exceeded" );
1045  }
1046  msg->offset++; // nullterm
1047  layoutlen++;
1048 
1049  u16 len = msg->offset;
1050  msg->offset = pos;
1051  msg->WriteFlipped<u16>( layoutlen );
1052  msg->offset = len;
1053 
1054  pos = msg->offset;
1055 
1056  if ( msg->offset + 2 > static_cast<int>( sizeof msg->buffer ) )
1057  {
1058  return new BError( "Buffer length exceeded" );
1059  }
1060  msg->offset += 2; // numlines
1061 
1062  u16 numlines = 0;
1063  for ( unsigned i = 0; i < data_arr->ref_arr.size(); ++i )
1064  {
1065  BObject* bo = data_arr->ref_arr[i].get();
1066  if ( bo == nullptr )
1067  continue;
1068  BObjectImp* imp = bo->impptr();
1069  std::string s = imp->getStringRep();
1070 
1071  const char* string = s.c_str();
1072  ++numlines;
1073  size_t textlen = s.length();
1074 
1075  if ( msg->offset + 2 + textlen * 2 > sizeof msg->buffer )
1076  {
1077  return new BError( "Buffer length exceeded" );
1078  }
1079 
1080  msg->WriteFlipped<u16>( textlen );
1081 
1082  while ( *string ) // unicode
1083  msg->Write<u16>( static_cast<u16>( ( *string++ ) << 8 ) );
1084  }
1085 
1086  if ( msg->offset + 1 > static_cast<int>( sizeof msg->buffer ) )
1087  {
1088  return new BError( "Buffer length exceeded" );
1089  }
1090  msg->offset++; // nullterm
1091 
1092  len = msg->offset;
1093  msg->offset = pos;
1094  msg->WriteFlipped<u16>( numlines );
1095  msg->offset = 1;
1096  msg->WriteFlipped<u16>( len );
1097 
1098  if ( !uoexec.suspend() )
1099  {
1100  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
1101  << "\tCall to function UO::SendDialogGump():\n"
1102  << "\tThe execution of this script can't be blocked!\n";
1103  return new Bscript::BError( "Script can't be blocked" );
1104  }
1105 
1106  msg.Send( chr->client, len );
1107  chr->client->gd->add_gumpmod( this, gumpid );
1108  // old_gump_uoemod = this;
1109  gump_chr = chr;
1110 
1111  return new BLong( 0 );
1112 }
1113 
1115  ObjArray* data_arr, int x, int y,
1116  u32 gumpid )
1117 {
1119  PktHelper::PacketOut<PktOut_DD> bfr; // compress buffer
1120  bfr->offset = 0;
1121  msg->offset += 2;
1122  msg->Write<u32>( chr->serial_ext );
1123  msg->WriteFlipped<u32>( gumpid );
1124  msg->WriteFlipped<u32>( static_cast<u16>( x ) );
1125  msg->WriteFlipped<u32>( static_cast<u16>( y ) );
1126  msg->offset += 8; // u32 layout_clen,layout_dlen
1127 
1128  u32 layoutdlen = 0;
1129 
1130  for ( unsigned i = 0; i < layout_arr->ref_arr.size(); ++i )
1131  {
1132  BObject* bo = layout_arr->ref_arr[i].get();
1133  if ( bo == nullptr )
1134  continue;
1135  BObjectImp* imp = bo->impptr();
1136  std::string s = imp->getStringRep();
1137 
1138  size_t addlen = 4 + s.length();
1139  if ( layoutdlen + addlen > sizeof bfr->buffer )
1140  {
1141  return new BError( "Buffer length exceeded" );
1142  }
1143  layoutdlen += static_cast<u32>( addlen );
1144  bfr->Write( "{ ", 2, false );
1145  bfr->Write( s.c_str(), static_cast<u16>( s.length() ), false );
1146  bfr->Write( " }", 2, false );
1147  }
1148  if ( layoutdlen + 1 > static_cast<u32>( sizeof bfr->buffer ) )
1149  {
1150  return new BError( "Buffer length exceeded" );
1151  }
1152  layoutdlen++;
1153  bfr->offset++; // nullterm
1154 
1155  unsigned long cbuflen =
1156  ( ( (unsigned long)( ( (float)( layoutdlen ) ) * 1.001f ) ) + 12 ); // as per zlib spec
1157  if ( cbuflen > ( (unsigned long)( 0xFFFF - msg->offset ) ) )
1158  {
1159  return new BError( "Compression error" );
1160  }
1161 
1162  if ( compress2( reinterpret_cast<unsigned char*>( msg->getBuffer() ), &cbuflen,
1163  reinterpret_cast<unsigned char*>( &bfr->buffer ), layoutdlen,
1164  Z_DEFAULT_COMPRESSION ) != Z_OK )
1165  {
1166  return new BError( "Compression error" );
1167  }
1168  msg->offset -= 8;
1169  msg->WriteFlipped<u32>( cbuflen + 4 );
1170  msg->WriteFlipped<u32>( layoutdlen );
1171  msg->offset += static_cast<u16>( cbuflen );
1172 
1173  bfr->offset = 0;
1174 
1175  u32 numlines = 0;
1176  u32 datadlen = 0;
1177 
1178  for ( unsigned i = 0; i < data_arr->ref_arr.size(); ++i )
1179  {
1180  BObject* bo = data_arr->ref_arr[i].get();
1181  if ( bo == nullptr )
1182  continue;
1183  BObjectImp* imp = bo->impptr();
1184  std::string s = imp->getStringRep();
1185 
1186  const char* string = s.c_str();
1187  ++numlines;
1188  size_t addlen = ( s.length() + 1 ) * 2;
1189  if ( datadlen + addlen > sizeof bfr->buffer )
1190  {
1191  return new BError( "Buffer length exceeded" );
1192  }
1193  datadlen += static_cast<u32>( addlen );
1194  bfr->WriteFlipped<u16>( s.length() );
1195  while ( *string ) // unicode
1196  bfr->Write<u16>( static_cast<u16>( ( *string++ ) << 8 ) );
1197  }
1198  msg->WriteFlipped<u32>( numlines );
1199  if ( numlines != 0 )
1200  {
1201  msg->offset += 8; // u32 text_clen, text_dlen
1202 
1203  cbuflen = ( ( (unsigned long)( ( (float)( datadlen ) ) * 1.001f ) ) + 12 ); // as per zlib spec
1204  if ( cbuflen > ( (unsigned long)( 0xFFFF - msg->offset ) ) )
1205  {
1206  return new BError( "Compression error" );
1207  }
1208  if ( compress2( reinterpret_cast<unsigned char*>( msg->getBuffer() ), &cbuflen,
1209  reinterpret_cast<unsigned char*>( &bfr->buffer ), datadlen,
1210  Z_DEFAULT_COMPRESSION ) != Z_OK )
1211  {
1212  return new BError( "Compression error" );
1213  }
1214 
1215  msg->offset -= 8;
1216  msg->WriteFlipped<u32>( cbuflen + 4 );
1217  msg->WriteFlipped<u32>( datadlen );
1218  msg->offset += static_cast<u16>( cbuflen );
1219  }
1220  else
1221  msg->Write<u32>( 0u );
1222  u16 len = msg->offset;
1223  msg->offset = 1;
1224  msg->WriteFlipped<u16>( len );
1225 
1226  if ( !uoexec.suspend() )
1227  {
1228  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
1229  << "\tCall to function UO::SendDialogGump():\n"
1230  << "\tThe execution of this script can't be blocked!\n";
1231  return new Bscript::BError( "Script can't be blocked" );
1232  }
1233 
1234  msg.Send( chr->client, len );
1235  chr->client->gd->add_gumpmod( this, gumpid );
1236  // old_gump_uoemod = this;
1237  gump_chr = chr;
1238 
1239  return new BLong( 0 );
1240 }
1241 
1242 class BIntHash : public BObjectImp
1243 {
1244 public:
1245  BIntHash();
1246  BIntHash( const BIntHash& );
1247  void add( int key, BObjectImp* value );
1248  virtual BObjectRef get_member( const char* membername ) POL_OVERRIDE;
1249  virtual BObjectRef OperSubscript( const BObject& obj ) POL_OVERRIDE;
1250  virtual BObjectImp* copy() const POL_OVERRIDE;
1251  virtual std::string getStringRep() const POL_OVERRIDE;
1252  virtual size_t sizeEstimate() const POL_OVERRIDE;
1253 
1254 private:
1255  typedef std::map<int, BObjectRef> Contents;
1256  Contents contents_;
1257 
1258  // not implemented:
1259  BIntHash& operator=( const BIntHash& );
1260 };
1261 
1262 BIntHash::BIntHash() : BObjectImp( OTUnknown ), contents_() {}
1263 
1265 
1267 {
1268  return new BIntHash( *this );
1269 }
1270 
1272 {
1273  size_t size =
1274  sizeof( BIntHash ) +
1275  ( sizeof( int ) + sizeof( BObjectRef ) + ( sizeof( void* ) * 3 + 1 ) / 2 ) * contents_.size();
1276  for ( const auto& p : contents_ )
1277  {
1278  size += p.second.sizeEstimate();
1279  }
1280  return size;
1281 }
1282 
1283 std::string BIntHash::getStringRep() const
1284 {
1285  return "<inthash>";
1286 }
1287 
1288 void BIntHash::add( int key, BObjectImp* value )
1289 {
1290  // contents_.insert( Contents::value_type( key, value ) );
1291  contents_[key].set( new BObject( value ) );
1292 }
1293 
1294 BObjectRef BIntHash::get_member( const char* membername )
1295 {
1296  if ( stricmp( membername, "keys" ) == 0 )
1297  {
1298  ObjArray* arr = new ObjArray;
1299  BObject obj( arr );
1300 
1301  Contents::const_iterator itr, end;
1302  for ( itr = contents_.begin(), end = contents_.end(); itr != end; ++itr )
1303  {
1304  int key = ( *itr ).first;
1305  arr->addElement( new BLong( key ) );
1306  }
1307 
1308  return BObjectRef( obj.impptr() );
1309  }
1310  else
1311  {
1312  return BObjectRef( new BError( "member not found" ) );
1313  }
1314 }
1315 
1317 {
1318  const BObjectImp& objimp = obj.impref();
1319  if ( objimp.isa( OTLong ) )
1320  {
1321  const BLong& lng = static_cast<const BLong&>( objimp );
1322  Contents::iterator itr = contents_.find( lng.value() );
1323  if ( itr != contents_.end() )
1324  {
1325  BObjectRef& oref = ( *itr ).second;
1326  return BObjectRef( oref.get()->impptr() );
1327  }
1328  else
1329  {
1330  return BObjectRef( new BError( "Key not found in inthash" ) );
1331  }
1332  }
1333  else
1334  {
1335  return BObjectRef( new BError( "Incorrect type used as subscript to inthash" ) );
1336  }
1337 }
1338 
1340 {
1341  uoemod->uoexec.os_module->revive();
1342  uoemod->gump_chr = nullptr;
1343  client->gd->remove_gumpmods( uoemod );
1344 }
1345 
1346 BObjectImp* UOExecutorModule::mf_CloseGump( /* who, pid, response := 0 */ )
1347 {
1348  Character* chr;
1349  unsigned int pid;
1350  BObjectImp* resp;
1351 
1352  if ( !( getCharacterParam( exec, 0, chr ) && exec.getParam( 1, pid ) &&
1353  ( getParamImp( 2, resp ) ) ) )
1354  {
1355  return new BError( "Invalid parameter" );
1356  }
1357 
1358  if ( !chr->has_active_client() )
1359  return new BError( "No client attached" );
1360 
1361  Client* client = chr->client;
1362 
1363  UOExecutorModule* uoemod = client->gd->find_gumpmod( pid );
1364  if ( uoemod == nullptr )
1365  {
1366  return new BError( "Couldnt find script" );
1367  }
1368 
1370  msg->WriteFlipped<u16>( 13u );
1371  msg->offset += 2;
1372  msg->WriteFlipped<u32>( pid );
1373  msg->offset += 4; // buttonid
1374 
1375  msg.Send( client );
1376 
1377  uoemod->uoexec.ValueStack.back().set( new BObject( resp ) );
1378  clear_gumphandler( client, uoemod );
1379 
1380  return new BLong( 1 );
1381 }
1382 
1384 {
1385  Character* chr;
1386  unsigned int type;
1387  UObject* obj;
1388 
1389  if ( !getCharacterParam( exec, 0, chr ) || !getParam( 1, type ) ||
1390  !getUObjectParam( exec, 2, obj ) )
1391  return new BError( "Invalid parameter" );
1392 
1393  if ( !chr->has_active_client() )
1394  return new BError( "No client attached" );
1395 
1396  if ( type == PKTBI_BF_16::CONTAINER )
1397  {
1398  if ( !obj->script_isa( POLCLASS_CONTAINER ) )
1399  return new BError( "Invalid object, has to be a containerRef" );
1400  }
1401  else if ( type == PKTBI_BF_16::PAPERDOLL || type == PKTBI_BF_16::STATUS ||
1402  type == PKTBI_BF_16::CHARPROFILE )
1403  {
1404  if ( !obj->script_isa( POLCLASS_MOBILE ) )
1405  return new BError( "Invalid object, has to be a mobRef" );
1406  }
1407  else
1408  return new BError( "Invalid type" );
1409 
1411  msg->WriteFlipped<u16>( 13u );
1412  msg->offset += 2; // sub
1413  msg->WriteFlipped<u32>( type );
1414  msg->Write<u32>( obj->serial_ext );
1415 
1416  msg.Send( chr->client );
1417 
1418  return new BLong( 1 );
1419 }
1420 
1421 void gumpbutton_handler( Client* client, PKTIN_B1* msg )
1422 {
1423  const u32 VIRTUE_GUMP_ID = 0x1CD;
1424 
1425  char* msgbuf = reinterpret_cast<char*>( msg );
1426  PKTIN_B1::HEADER* hdr = reinterpret_cast<PKTIN_B1::HEADER*>( msg );
1427  unsigned short msglen = cfBEu16( hdr->msglen );
1428 
1429  u32 gumpid = cfBEu32( hdr->dialogid );
1430  u32 buttonid = cfBEu32( hdr->buttonid );
1431 
1432  // When the player double-clicks the virtue pentagram icon in its paperdoll, an unexpected
1433  // PKTIN_B1 gump reply packet with dialogid == 0x01CD and buttonid == 1 will be sent to us
1434  if ( gumpid == VIRTUE_GUMP_ID )
1435  {
1436  if ( hdr->serial == client->chr->serial_ext )
1437  {
1438  if ( buttonid == 1 )
1439  {
1440  PKTIN_B1::INTS_HEADER* intshdr_ = reinterpret_cast<PKTIN_B1::INTS_HEADER*>( hdr + 1 );
1441  if ( cfBEu32( intshdr_->count ) == 1 )
1442  {
1443  PKTIN_B1::INT_ENTRY* intentries_ = reinterpret_cast<PKTIN_B1::INT_ENTRY*>( intshdr_ + 1 );
1444  if ( intentries_->value == client->chr->serial_ext )
1445  {
1447  "misc/virtuebutton", true, Plib::systemstate.config.cache_interactive_scripts );
1448  if ( prog.get() != nullptr )
1449  client->chr->start_script( prog.get(), false );
1450  return;
1451  }
1452  }
1453  }
1454  }
1455  }
1456 
1457 
1458  UOExecutorModule* uoemod = client->gd->find_gumpmod( gumpid );
1459  if ( uoemod == nullptr )
1460  {
1461  POLLOG_INFO.Format(
1462  "\nWarning: Character 0x{:X} sent an unexpected gump menu selection. Gump ID 0x{:X}, "
1463  "button ID 0x{:X}\n" )
1464  << client->chr->serial << gumpid << buttonid;
1465  return;
1466  }
1467 
1468 
1469  if ( msglen <=
1470  0x0f ) // Using == instead of <= should do the trick, but i think <= is more robust
1471  {
1472  // The virtue button packet is 15 bytes long: it will not carry a switchcount/INTS_HEADER,
1473  // so prevent full processing code to overflow and save some CPU cycles meanwhile.
1474  // Maybe other packets could be that short too?
1475  if ( buttonid == 0 )
1476  {
1477  uoemod->uoexec.ValueStack.back().set( new BObject( new BLong( 0 ) ) );
1478  }
1479  else
1480  {
1481  std::unique_ptr<BIntHash> hash( new BIntHash );
1482  hash->add( 0, new BLong( buttonid ) );
1483  hash->add( buttonid, new BLong( 1 ) );
1484  uoemod->uoexec.ValueStack.back().set( new BObject( hash.release() ) );
1485  }
1486  }
1487  else
1488  {
1489  // Process rest of the packet
1490  PKTIN_B1::INTS_HEADER* intshdr = reinterpret_cast<PKTIN_B1::INTS_HEADER*>( hdr + 1 );
1491  u32 ints_count = cfBEu32( intshdr->count );
1492  unsigned stridx = sizeof( PKTIN_B1::HEADER ) + sizeof( PKTIN_B1::INTS_HEADER ) +
1493  sizeof( PKTIN_B1::INT_ENTRY ) * ints_count +
1494  sizeof( PKTIN_B1::STRINGS_HEADER );
1495  if ( stridx > msglen )
1496  {
1497  ERROR_PRINT << "Blech! B1 message specified too many ints!\n";
1498  clear_gumphandler( client, uoemod );
1499  return;
1500  }
1501  PKTIN_B1::INT_ENTRY* intentries = reinterpret_cast<PKTIN_B1::INT_ENTRY*>( intshdr + 1 );
1502  PKTIN_B1::STRINGS_HEADER* strhdr =
1503  reinterpret_cast<PKTIN_B1::STRINGS_HEADER*>( intentries + ints_count );
1504  u32 strings_count = cfBEu32( strhdr->count );
1505  // even if this is ok, it could still overflow. Have to check each string.
1506  if ( stridx + ( sizeof( PKTIN_B1::STRING_ENTRY ) - 1 ) * strings_count > msglen + 1u )
1507  {
1508  ERROR_PRINT << "Client (Account " << client->acct->name() << ", Character "
1509  << client->chr->name()
1510  << ") Blech! B1 message specified too many ints and/or strings!\n";
1511  uoemod->uoexec.ValueStack.back().set(
1512  new BObject( new BError( "B1 message specified too many ints and/or strings." ) ) );
1513  clear_gumphandler( client, uoemod );
1514  return;
1515  }
1516 
1517  if ( ints_count == 0 && strings_count == 0 && buttonid == 0 )
1518  {
1519  uoemod->uoexec.ValueStack.back().set( new BObject( new BLong( 0 ) ) );
1520  }
1521  else
1522  {
1523  std::unique_ptr<BIntHash> hash( new BIntHash );
1524  hash->add( 0, new BLong( buttonid ) );
1525  hash->add( buttonid, new BLong( 1 ) );
1526  for ( unsigned i = 0; i < ints_count; ++i )
1527  {
1528  hash->add( cfBEu32( intentries[i].value ), new BLong( 1 ) );
1529  }
1530  for ( unsigned i = 0; i < strings_count; ++i )
1531  {
1532  PKTIN_B1::STRING_ENTRY* strentry =
1533  reinterpret_cast<PKTIN_B1::STRING_ENTRY*>( msgbuf + stridx );
1534  unsigned short length = cfBEu16( strentry->length );
1535  stridx += offsetof( PKTIN_B1::STRING_ENTRY, data ) + length * 2;
1536  if ( stridx > msglen )
1537  {
1538  ERROR_PRINT << "Client (Account " << client->acct->name() << ", Character "
1539  << client->chr->name()
1540  << ") Blech! B1 message strings overflow message buffer!\n";
1541  break;
1542  }
1543  std::string str;
1544  str = Clib::decint( cfBEu16( strentry->tag ) ) + ": ";
1545  str.reserve( length + str.size() );
1546  u8 c;
1547  for ( int si = 0; si < length; ++si ) // ENHANCE: Handle Unicode strings properly (add a
1548  // "uc" member somewhere for each returned string
1549  // that doesn't break existing code)
1550  {
1551  c = strentry->data[si * 2 + 1];
1552  if ( c >= 0x20 ) // dave added 4/13/3, strip control characters
1553  str.append( 1, c );
1554  }
1555  // oops we're throwing away tag!
1556  hash->add( cfBEu16( strentry->tag ), new String( str ) );
1557  }
1558  uoemod->uoexec.ValueStack.back().set( new BObject( hash.release() ) );
1559  }
1560  }
1561 
1562  clear_gumphandler( client, uoemod );
1563 }
1564 
1566 {
1567  Character* chr;
1568  const String* line1;
1569  int cancel;
1570  int style;
1571  int maximum;
1572  const String* line2;
1573 
1574  if ( !( getCharacterParam( exec, 0, chr ) && exec.getStringParam( 1, line1 ) &&
1575  exec.getParam( 2, cancel ) && exec.getParam( 3, style ) && exec.getParam( 4, maximum ) &&
1576  exec.getStringParam( 5, line2 ) ) )
1577  {
1578  return new BError( "Invalid parameter" );
1579  }
1580  if ( !chr->has_active_client() )
1581  {
1582  return new BError( "No client attached" );
1583  }
1584 
1586  msg->offset += 2;
1587  msg->Write<u32>( chr->serial_ext );
1588  msg->offset += 2; // u8 type,index
1589 
1590  size_t numbytes = line1->length() + 1;
1591  if ( numbytes > 256 )
1592  numbytes = 256;
1593  msg->WriteFlipped<u16>( numbytes );
1594  msg->Write( line1->data(), static_cast<u16>( numbytes ) ); // null-terminated
1595 
1596  msg->Write<u8>( static_cast<u8>( cancel ) );
1597  msg->Write<u8>( static_cast<u8>( style ) );
1598  msg->WriteFlipped<s32>( maximum );
1599  numbytes = line2->length() + 1;
1600  if ( numbytes > 256 )
1601  numbytes = 256;
1602  msg->WriteFlipped<u16>( numbytes );
1603  msg->Write( line2->data(), static_cast<u16>( numbytes ) ); // null-terminated
1604  u16 len = msg->offset;
1605  msg->offset = 1;
1606  msg->WriteFlipped<u16>( len );
1607 
1608  if ( !uoexec.suspend() )
1609  {
1610  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
1611  << "\tCall to function UO::SendTextEntryGump():\n"
1612  << "\tThe execution of this script can't be blocked!\n";
1613  return new Bscript::BError( "Script can't be blocked" );
1614  }
1615 
1616  msg.Send( chr->client, len );
1617  chr->client->gd->textentry_uoemod = this;
1618  textentry_chr = chr;
1619 
1620  return new BLong( 0 );
1621 }
1622 
1623 void handle_textentry( Client* client, PKTIN_AC* msg )
1624 {
1625  if ( client->gd->textentry_uoemod == nullptr )
1626  {
1627  ERROR_PRINT << "Client (Account " << client->chr->acct->name() << ", Character "
1628  << client->chr->name() << ")used out-of-sequence textentry command?\n";
1629  return;
1630  }
1631  BObjectImp* resimp = new BLong( 0 );
1632  if ( msg->retcode == PKTIN_AC::RETCODE_OKAY )
1633  {
1634  unsigned short datalen = cfBEu16( msg->datalen );
1635  if ( datalen >= 1 && datalen <= 256 && msg->data[datalen - 1] == '\0' )
1636  {
1637  // dave added isprint checking 4/13/3
1638  bool ok = true;
1639  --datalen; // don't include null terminator (already checked)
1640  for ( int i = 0; i < datalen; ++i )
1641  {
1642  if ( !isprint( msg->data[i] ) )
1643  {
1644  ok = false;
1645  break;
1646  }
1647  }
1648  if ( ok )
1649  {
1650  resimp = new String( msg->data, datalen );
1651  }
1652  }
1653  }
1654 
1655  client->gd->textentry_uoemod->uoexec.ValueStack.back().set( new BObject( resimp ) );
1656  client->gd->textentry_uoemod->uoexec.os_module->revive();
1657  client->gd->textentry_uoemod->textentry_chr = nullptr;
1658  client->gd->textentry_uoemod = nullptr;
1659 }
1660 
1661 class PolCore : public BObjectImp
1662 {
1663 public:
1664  PolCore();
1665  virtual BObjectRef get_member( const char* membername ) POL_OVERRIDE;
1666  virtual BObjectImp* call_method( const char* methodname, Executor& ex ) POL_OVERRIDE;
1667  virtual BObjectImp* copy() const POL_OVERRIDE;
1668  virtual std::string getStringRep() const POL_OVERRIDE;
1669  virtual size_t sizeEstimate() const POL_OVERRIDE { return sizeof( PolCore ); }
1670  virtual const char* typeOf() const POL_OVERRIDE;
1671  virtual u8 typeOfInt() const POL_OVERRIDE;
1672 
1673 private:
1674  // not implemented:
1675  PolCore& operator=( const PolCore& );
1676 };
1677 
1679 
1681 {
1682  return new PolCore;
1683 }
1684 
1685 std::string PolCore::getStringRep() const
1686 {
1687  return "<polcore>";
1688 }
1689 
1690 const char* PolCore::typeOf() const
1691 {
1692  return "PolCoreRef";
1693 }
1695 {
1696  return OTPolCoreRef;
1697 }
1698 
1700 {
1701  std::unique_ptr<ObjArray> arr( new ObjArray );
1702  for ( Plib::Packages::iterator itr = Plib::systemstate.packages.begin();
1703  itr != Plib::systemstate.packages.end(); ++itr )
1704  {
1705  Plib::Package* pkg = ( *itr );
1706  arr->addElement( new String( pkg->name() ) );
1707  }
1708  return arr.release();
1709 }
1710 
1711 void add_script( ObjArray* arr, UOExecutor* uoexec, const char* /*state*/ )
1712 {
1713  arr->addElement( new ScriptExObjImp( uoexec ) );
1714 }
1715 
1717 {
1718  ObjArray* arr = new ObjArray;
1719 
1720  const ExecList& runlist = scriptScheduler.getRunlist();
1721  const ExecList& ranlist = scriptScheduler.getRanlist();
1722 
1723  for ( const auto& script : ranlist )
1724  {
1725  add_script( arr, script, "Running" );
1726  }
1727  for ( const auto& script : runlist )
1728  {
1729  add_script( arr, script, "Running" );
1730  }
1731  return arr;
1732 }
1733 
1735 {
1736  ObjArray* arr = new ObjArray;
1737 
1738  const ExecList& runlist = scriptScheduler.getRunlist();
1739  const ExecList& ranlist = scriptScheduler.getRanlist();
1740  const HoldList& holdlist = scriptScheduler.getHoldlist();
1741  const NoTimeoutHoldList& notimeoutholdlist = scriptScheduler.getNoTimeoutHoldlist();
1742 
1743  for ( const auto& script : ranlist )
1744  {
1745  add_script( arr, script, "Running" );
1746  }
1747  for ( const auto& script : runlist )
1748  {
1749  add_script( arr, script, "Running" );
1750  }
1751  for ( const auto& script : holdlist )
1752  {
1753  add_script( arr, ( script ).second, "Sleeping" );
1754  }
1755  for ( const auto& script : notimeoutholdlist )
1756  {
1757  add_script( arr, script, "Sleeping" );
1758  }
1759  return arr;
1760 }
1761 
1763 {
1764  std::unique_ptr<ObjArray> arr = Clib::make_unique<ObjArray>();
1765 
1766  u64 total_instr = 0;
1767  for ( const auto& source : scriptScheduler.scrstore )
1768  {
1769  EScriptProgram* eprog = ( ( source ).second ).get();
1770  total_instr += eprog->instr_cycles;
1771  }
1772 
1773  for ( const auto& src : scriptScheduler.scrstore )
1774  {
1775  EScriptProgram* eprog = ( ( src ).second ).get();
1776 
1777 
1778  std::unique_ptr<BStruct> elem = Clib::make_unique<BStruct>();
1779  elem->addMember( "name", new String( eprog->name ) );
1780  elem->addMember( "instr", new Double( static_cast<double>( eprog->instr_cycles ) ) );
1781  elem->addMember( "invocations", new BLong( eprog->invocations ) );
1782  u64 cycles_per_invoc = eprog->instr_cycles / ( eprog->invocations ? eprog->invocations : 1 );
1783  elem->addMember( "instr_per_invoc", new Double( static_cast<double>( cycles_per_invoc ) ) );
1784  double cycle_percent =
1785  total_instr != 0 ? ( static_cast<double>( eprog->instr_cycles ) / total_instr * 100.0 ) : 0;
1786  elem->addMember( "instr_percent", new Double( cycle_percent ) );
1787 
1788  arr->addElement( elem.release() );
1789  }
1790  return arr.release();
1791 }
1792 
1794 {
1795  std::unique_ptr<BStruct> arr( new BStruct );
1796 
1797  ObjArray* sent = new ObjArray;
1798  arr->addMember( "sent", sent );
1799 
1800  ObjArray* received = new ObjArray;
1801  arr->addMember( "received", received );
1802 
1803  for ( unsigned i = 0; i < 256; ++i )
1804  {
1805  std::unique_ptr<BStruct> elem = Clib::make_unique<BStruct>();
1806  elem->addMember( "count", new BLong( stats.sent[i].count ) );
1807  elem->addMember( "bytes", new BLong( stats.sent[i].bytes ) );
1808  sent->addElement( elem.release() );
1809  }
1810 
1811  for ( unsigned i = 0; i < 256; ++i )
1812  {
1813  std::unique_ptr<BStruct> elem( new BStruct );
1814  elem->addMember( "count", new BLong( stats.received[i].count ) );
1815  elem->addMember( "bytes", new BLong( stats.received[i].bytes ) );
1816  received->addElement( elem.release() );
1817  }
1818 
1819  return arr.release();
1820 }
1821 
1823 {
1824  return GetIoStatsObj( Core::networkManager.iostats );
1825 }
1826 
1828 {
1829  return GetIoStatsObj( Core::networkManager.queuedmode_iostats );
1830 }
1831 
1833 {
1834  using namespace PacketWriterDefs;
1835  std::unique_ptr<ObjArray> pkts = Clib::make_unique<ObjArray>();
1836  PacketQueueMap* map = networkManager.packetsSingleton->getPackets();
1837  for ( PacketQueueMap::iterator it = map->begin(); it != map->end(); ++it )
1838  {
1839  std::unique_ptr<BStruct> elem( new BStruct );
1840  elem->addMember( "pkt", new BLong( it->first ) );
1841  elem->addMember( "count", new BLong( static_cast<int>( it->second->Count() ) ) );
1842  pkts->addElement( elem.release() );
1843  if ( it->second->HasSubs() )
1844  {
1845  PacketInterfaceQueueMap* submap = it->second->GetSubs();
1846  for ( PacketInterfaceQueueMap::iterator s_it = submap->begin(); s_it != submap->end();
1847  ++s_it )
1848  {
1849  std::unique_ptr<BStruct> elemsub( new BStruct );
1850  elemsub->addMember( "pkt", new BLong( it->first ) );
1851  elemsub->addMember( "sub", new BLong( s_it->first ) );
1852  elemsub->addMember( "count", new BLong( static_cast<int>( s_it->second.size() ) ) );
1853  pkts->addElement( elemsub.release() );
1854  }
1855  }
1856  }
1857  return pkts.release();
1858 }
1859 
1860 BObjectImp* GetCoreVariable( const char* corevar )
1861 {
1862 #define LONG_COREVAR( name, expr ) \
1863  if ( stricmp( corevar, #name ) == 0 ) \
1864  return new BLong( static_cast<int>( expr ) );
1865 
1866  if ( stricmp( corevar, "itemcount" ) == 0 )
1867  return new BLong( get_toplevel_item_count() );
1868  if ( stricmp( corevar, "mobilecount" ) == 0 )
1869  return new BLong( get_mobile_count() );
1870 
1871  if ( stricmp( corevar, "bytes_sent" ) == 0 )
1872  return new Double( static_cast<double>( networkManager.polstats.bytes_sent ) );
1873  if ( stricmp( corevar, "bytes_received" ) == 0 )
1874  return new Double( static_cast<double>( networkManager.polstats.bytes_received ) );
1875 
1876  LONG_COREVAR( uptime, polclock() / POLCLOCKS_PER_SEC );
1879  // LONG_COREVAR( bytes_sent, polstats.bytes_sent );
1880  // LONG_COREVAR( bytes_received, polstats.bytes_received );
1881  LONG_COREVAR( version, POL_VERSION );
1882  LONG_COREVAR( systime, time( nullptr ) );
1883  LONG_COREVAR( events_per_min, GET_PROFILEVAR_PER_MIN( events ) );
1884  LONG_COREVAR( skill_checks_per_min, GET_PROFILEVAR_PER_MIN( skill_checks ) );
1885  LONG_COREVAR( combat_operations_per_min, GET_PROFILEVAR_PER_MIN( combat_operations ) );
1886  LONG_COREVAR( error_creations_per_min, GET_PROFILEVAR_PER_MIN( error_creations ) );
1887 
1888  LONG_COREVAR( tasks_ontime_per_min, GET_PROFILEVAR_PER_MIN( tasks_ontime ) );
1889  LONG_COREVAR( tasks_late_per_min, GET_PROFILEVAR_PER_MIN( tasks_late ) );
1890  LONG_COREVAR( tasks_late_ticks_per_min, GET_PROFILEVAR_PER_MIN( tasks_late_ticks ) );
1891 
1892  LONG_COREVAR( scripts_late_per_min, GET_PROFILEVAR_PER_MIN( scripts_late ) );
1893  LONG_COREVAR( scripts_ontime_per_min, GET_PROFILEVAR_PER_MIN( scripts_ontime ) );
1894 
1895  LONG_COREVAR( instr_per_min, stateManager.profilevars.last_sipm );
1896  LONG_COREVAR( priority_divide, scriptScheduler.priority_divide );
1897  if ( stricmp( corevar, "verstr" ) == 0 )
1898  return new String( POL_VERSION_ID );
1899  if ( stricmp( corevar, "compiledatetime" ) == 0 )
1901  if ( stricmp( corevar, "packages" ) == 0 )
1902  return GetPackageList();
1903  if ( stricmp( corevar, "running_scripts" ) == 0 )
1904  return GetRunningScriptList();
1905  if ( stricmp( corevar, "all_scripts" ) == 0 )
1906  return GetAllScriptList();
1907  if ( stricmp( corevar, "script_profiles" ) == 0 )
1908  return GetScriptProfiles();
1909  if ( stricmp( corevar, "iostats" ) == 0 )
1910  return GetIoStats();
1911  if ( stricmp( corevar, "queued_iostats" ) == 0 )
1912  return GetQueuedIoStats();
1913  if ( stricmp( corevar, "pkt_status" ) == 0 )
1914  return GetPktStatusObj();
1915  if ( stricmp( corevar, "memory_usage" ) == 0 )
1916  return new BLong( static_cast<int>( Clib::getCurrentMemoryUsage() / 1024 ) );
1917 
1918  return new BError( std::string( "Unknown core variable " ) + corevar );
1919 }
1920 
1921 BObjectRef PolCore::get_member( const char* membername )
1922 {
1923  return BObjectRef( GetCoreVariable( membername ) );
1924 }
1925 
1926 BObjectImp* PolCore::call_method( const char* methodname, Executor& ex )
1927 {
1928  if ( stricmp( methodname, "log_profile" ) == 0 )
1929  {
1930  if ( ex.numParams() != 1 )
1931  return new BError( "polcore.log_profile(clear) requires 1 parameter." );
1932  int clear;
1933  if ( ex.getParam( 0, clear ) )
1934  {
1935  log_all_script_cycle_counts( clear ? true : false );
1936  return new BLong( 1 );
1937  }
1938  }
1939  else if ( stricmp( methodname, "set_priority_divide" ) == 0 )
1940  {
1941  if ( ex.numParams() != 1 )
1942  return new BError( "polcore.set_priority_divide(value) requires 1 parameter." );
1943  int div;
1944  if ( ex.getParam( 0, div, 1, 1000 ) )
1945  {
1947  return new BLong( 1 );
1948  }
1949  else
1950  {
1951  return nullptr;
1952  }
1953  }
1954  else if ( stricmp( methodname, "clear_script_profile_counters" ) == 0 )
1955  {
1956  if ( ex.numParams() > 0 )
1957  return new BError( "polcore.clear_script_profile_counters() doesn't take parameters." );
1959  return new BLong( 1 );
1960  }
1961  else if ( stricmp( methodname, "internal" ) == 0 ) // Just for internal Development...
1962  {
1963  int type;
1964  if ( ex.getParam( 0, type ) )
1965  {
1966 #ifdef MEMORYLEAK
1967  if ( type == 1 )
1968  {
1969  char buffer[30];
1970  auto time_tm = Clib::localtime( time( nullptr ) );
1971 
1972  strftime( buffer, sizeof buffer, "%m/%d %H:%M:%S", &time_tm );
1973  DEBUGLOG << "[" << buffer << "] polcore().internal\n";
1974  LEAKLOG << buffer << ";";
1975 
1976  bobject_alloc.log_stuff( "bobject" );
1977  uninit_alloc.log_stuff( "uninit" );
1978  blong_alloc.log_stuff( "blong" );
1979  double_alloc.log_stuff( "double" );
1980  ConfigFiles_log_stuff();
1981  Clib::PrintHeapData(); // Will print endl in llog
1982  }
1983 #endif
1984 #ifdef ESCRIPT_PROFILE
1985  DEBUGLOG << "FuncName,Count,Min,Max,Sum,Avarage\n";
1986  for ( escript_profile_map::iterator itr = EscriptProfileMap.begin();
1987  itr != EscriptProfileMap.end(); ++itr )
1988  {
1989  DEBUGLOG << itr->first << "," << itr->second.count << "," << itr->second.min << ","
1990  << itr->second.max << "," << itr->second.sum << ","
1991  << ( itr->second.sum / ( 1.0 * itr->second.count ) ) << "\n";
1992  }
1993 #endif
1994  if ( type == 2 )
1995  {
1997  }
1998  else if ( type == 3 )
1999  {
2000  POLLOG_ERROR << "Forcing crash\n";
2001  int* i = 0;
2002  *i = 1;
2003  }
2004  else if ( type == 4 )
2005  {
2006  POLLOG_ERROR << "Forcing assert crash\n";
2007  passert_always( false );
2008  }
2009  return new BLong( 1 );
2010  }
2011  else
2012  return new BError( "polcore.internal(value) requires 1 parameter." );
2013  }
2014  return nullptr;
2015 }
2016 
2018 {
2019  return new PolCore;
2020 }
2021 
2023 {
2024  ObjArray* arr = new ObjArray;
2025  return arr;
2026 }
2027 
2028 
2030 {
2031  const String* acctname;
2032  const String* password;
2033  int enabled;
2034  if ( getStringParam( 0, acctname ) && getStringParam( 1, password ) && getParam( 2, enabled ) )
2035  {
2036  if ( acctname->SafeCharAmt() < acctname->length() )
2037  {
2038  return new BError(
2039  "Attempted to use username in account creation with non-allowed characters." );
2040  }
2041  if ( password->SafeCharAmt() < password->length() )
2042  {
2043  return new BError(
2044  "Attempted to use password in account creation with non-allowed characters." );
2045  }
2046 
2047  if ( Accounts::find_account( acctname->data() ) )
2048  {
2049  return new BError( "Account already exists" );
2050  }
2051 
2052  // Dave 6/5/3 let this function handle the hashing (Account ctor does it)
2053  Accounts::Account* acct = Accounts::create_new_account( acctname->value(), password->value(),
2054  enabled ? true : false ); // MD5
2055 
2057  }
2058  else
2059  {
2060  return new BError( "Invalid parameter type" );
2061  }
2062 }
2063 
2065 {
2066  const String* acctname;
2067  if ( getStringParam( 0, acctname ) )
2068  {
2069  Accounts::Account* acct = Accounts::find_account( acctname->data() );
2070  if ( acct != nullptr )
2071  {
2073  }
2074  else
2075  {
2076  return new BError( "Account not found." );
2077  }
2078  }
2079  else
2080  {
2081  return new BError( "Invalid parameter type" );
2082  }
2083 }
2084 
2086 {
2087  std::unique_ptr<ObjArray> arr( new ObjArray );
2088  for ( unsigned idx = 0; idx < gamestate.accounts.size(); idx++ )
2089  {
2090  arr->addElement( new String( gamestate.accounts[idx]->name() ) );
2091  }
2092  return arr.release();
2093 }
2094 
2096 {
2097  if ( msg->choice )
2098  {
2099  INFO_PRINT << "Resurrect Menu Choice: " << int( msg->choice ) << "\n";
2100  // transmit( client, msg, sizeof *msg );
2101  }
2102 
2103  if ( client->chr != nullptr && client->gd != nullptr && client->gd->resurrect_uoemod != nullptr )
2104  {
2105  client->gd->resurrect_uoemod->uoexec.ValueStack.back().set(
2106  new BObject( new BLong( msg->choice ) ) );
2107  client->gd->resurrect_uoemod->uoexec.os_module->revive();
2108  client->gd->resurrect_uoemod->resurrect_chr = nullptr;
2109  client->gd->resurrect_uoemod = nullptr;
2110  }
2111 }
2112 
2114 {
2115  Character* chr;
2116  if ( !getCharacterParam( exec, 0, chr ) )
2117  return new BError( "Invalid parameter type" );
2118  if ( !chr->has_active_client() )
2119  return new BError( "No client attached" );
2120  if ( chr->client->gd->resurrect_uoemod != nullptr )
2121  return new BError( "Client busy with another instares dialog" );
2122 
2123  if ( !uoexec.suspend() )
2124  {
2125  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
2126  << "\tCall to function UO::SendInstaResDialog():\n"
2127  << "\tThe execution of this script can't be blocked!\n";
2128  return new Bscript::BError( "Script can't be blocked" );
2129  }
2130 
2132  msg->Write<u8>( RESURRECT_CHOICE_SELECT );
2133  msg.Send( chr->client );
2134  chr->client->gd->resurrect_uoemod = this;
2135  resurrect_chr = chr;
2136 
2137  return new BLong( 0 );
2138 }
2139 
2140 void handle_selcolor( Client* client, PKTBI_95* msg )
2141 {
2142  if ( client->chr != nullptr && client->gd != nullptr && client->gd->selcolor_uoemod != nullptr )
2143  {
2144  unsigned short color = cfBEu16( msg->graphic_or_color ) & VALID_ITEM_COLOR_MASK;
2145  BObject* valstack;
2146  if ( color >= 2 && color <= 1001 )
2147  {
2148  valstack = new BObject( new BLong( color ) );
2149  }
2150  else
2151  {
2152  valstack = new BObject( new BError( "Client selected an out-of-range color" ) );
2153 
2154  // unsigned short newcolor = ((color - 2) % 1000) + 2;
2155  POLLOG_ERROR.Format( "Client #{:d} (account {}) selected an out-of-range color 0x{:X}\n" )
2156  << static_cast<unsigned long>( client->instance_ )
2157  << ( ( client->acct != nullptr ) ? client->acct->name() : "unknown" ) << color;
2158  }
2159 
2160  // client->gd->selcolor_uoemod->uoexec.ValueStack.back().set( new BObject( new BLong( color ) )
2161  // );
2162  client->gd->selcolor_uoemod->uoexec.ValueStack.back().set( valstack );
2163  client->gd->selcolor_uoemod->uoexec.os_module->revive();
2164  client->gd->selcolor_uoemod->selcolor_chr = nullptr;
2165  client->gd->selcolor_uoemod = nullptr;
2166  }
2167 }
2168 
2169 
2171 {
2172  Character* chr;
2173  Item* item;
2174  if ( !getCharacterParam( exec, 0, chr ) || !getItemParam( exec, 1, item ) )
2175  {
2176  return new BError( "Invalid parameter type" );
2177  }
2178  if ( !chr->has_active_client() )
2179  return new BError( "No client attached" );
2180  if ( chr->client->gd->resurrect_uoemod != nullptr )
2181  return new BError( "Client is already selecting a color" );
2182 
2184  msg->Write<u32>( item->serial_ext );
2185  msg->offset += 2; // u16 unk
2186  msg->WriteFlipped<u16>( item->graphic );
2187 
2188  if ( !uoexec.suspend() )
2189  {
2190  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
2191  << "\tCall to function UO::SelectColor():\n"
2192  << "\tThe execution of this script can't be blocked!\n";
2193  return new Bscript::BError( "Script can't be blocked" );
2194  }
2195 
2196  msg.Send( chr->client );
2197 
2198  chr->client->gd->selcolor_uoemod = this;
2199  selcolor_chr = chr;
2200  return new BLong( 0 );
2201 }
2202 
2204 {
2205  Character* chr;
2206  Item* book;
2207 
2208  if ( !( getCharacterParam( exec, 0, chr ) && getItemParam( exec, 1, book ) ) )
2209  {
2210  return new BError( "Invalid parameter type" );
2211  }
2212  if ( !chr->has_active_client() )
2213  {
2214  return new BError( "No active client" );
2215  }
2216 
2217  bool writable = book->call_custom_method( "iswritable" )->isTrue();
2218  BObject nlines_ob( book->call_custom_method( "getnumlines" ) );
2219  int nlines;
2220  if ( nlines_ob.isa( BObjectImp::OTLong ) )
2221  {
2222  BLong* blong = static_cast<BLong*>( nlines_ob.impptr() );
2223  nlines = blong->value();
2224  }
2225  else
2226  {
2227  return new BError( "book.GetNumLines() did not return an Integer" );
2228  }
2229  std::string title = book->call_custom_method( "gettitle" )->getStringRep();
2230  std::string author = book->call_custom_method( "getauthor" )->getStringRep();
2231 
2232  int npages = ( nlines + 7 ) / 8;
2233 
2234  BObject contents_ob( UninitObject::create() );
2235  if ( writable )
2236  {
2237  contents_ob.setimp( book->call_custom_method( "getcontents" ).impptr() );
2238  if ( !contents_ob.isa( BObjectImp::OTArray ) )
2239  {
2240  if ( contents_ob.isa( BObjectImp::OTError ) )
2241  return contents_ob->copy();
2242  else
2243  return new BError( "book.GetContents() must return an array" );
2244  }
2245  }
2246 
2248  msg93->Write<u32>( book->serial_ext );
2249  msg93->Write<u8>( writable ? 1u : 0u );
2250  msg93->Write<u8>( 1u );
2251  msg93->WriteFlipped<u16>( static_cast<u16>( npages ) );
2252  msg93->Write( title.c_str(), 60, false );
2253  msg93->Write( author.c_str(), 30, false );
2254  msg93.Send( chr->client );
2255 
2256  if ( writable )
2257  {
2259  msg->offset += 2;
2260  msg->Write<u32>( book->serial_ext );
2261  msg->WriteFlipped<u16>( static_cast<u16>( npages ) );
2262 
2263  ObjArray* arr = static_cast<ObjArray*>( contents_ob.impptr() );
2264 
2265  int linenum = 1;
2266  for ( int page = 1; page <= npages; ++page )
2267  {
2268  if ( msg->offset + 4 > static_cast<int>( sizeof msg->buffer ) )
2269  {
2270  return new BError( "Buffer overflow" );
2271  }
2272  msg->WriteFlipped<u16>( static_cast<u16>( page ) );
2273  u16 offset = msg->offset;
2274  msg->offset += 2;
2275 
2276  int pagelines;
2277  for ( pagelines = 0; pagelines < 8 && linenum <= nlines; ++pagelines, ++linenum )
2278  {
2279  const BObjectImp* line_imp = arr->imp_at( linenum );
2280  std::string linetext;
2281  if ( line_imp )
2282  linetext = line_imp->getStringRep();
2283  if ( msg->offset + linetext.size() + 1 > sizeof msg->buffer )
2284  {
2285  return new BError( "Buffer overflow" );
2286  }
2287  msg->Write( linetext.c_str(), static_cast<u16>( linetext.size() + 1 ) );
2288  }
2289  u16 len = msg->offset;
2290  msg->offset = offset;
2291  msg->WriteFlipped<u16>( static_cast<u16>( pagelines ) );
2292  msg->offset = len;
2293  }
2294 
2295  /*
2296  int linenum = 1;
2297  for( int page = 1; page <= npages; ++page )
2298  {
2299  PKTBI_66_CONTENTS* ppage = reinterpret_cast<PKTBI_66_CONTENTS*>(&buffer[msglen]);
2300  msglen += sizeof(*ppage);
2301  if (msglen > sizeof buffer)
2302  return new BError( "Buffer overflow" );
2303  ppage->page = ctBEu16( page );
2304 
2305  int pagelines;
2306  for( pagelines = 0; pagelines < 8 && linenum <= nlines; ++pagelines, ++linenum )
2307  {
2308  string linetext;
2309 
2310  BObjectVec params;
2311  params.push_back( BObject(new BLong(linenum)) );
2312  BObject line_ob = book->call_custom_method( "getline", params );
2313  linetext = line_ob->getStringRep();
2314 
2315  char* linebuf = reinterpret_cast<char*>(&buffer[msglen]);
2316  msglen += linetext.size()+1;
2317  if (msglen > sizeof buffer)
2318  return new BError( "Buffer overflow" );
2319  memcpy( linebuf, linetext.c_str(), linetext.size()+1 );
2320  }
2321  ppage->lines = ctBEu16( pagelines );
2322  }
2323  */
2324  u16 len = msg->offset;
2325  msg->offset = 1;
2326  msg->WriteFlipped<u16>( len );
2327  msg.Send( chr->client, len );
2328  }
2329 
2330  return new BLong( 1 );
2331 }
2332 
2334 {
2335  unsigned int book_serial = cfBEu32( msg->book_serial );
2336  u16 page = cfBEu16( msg->page );
2337  Item* book = find_legal_item( client->chr, book_serial );
2338  if ( book == nullptr )
2339  {
2340  POLLOG.Format( "Unable to find book 0x{:X} for character 0x{:X}\n" )
2341  << book_serial << client->chr->serial;
2342  return;
2343  }
2344 
2345  if ( msg->lines == 0xFFFF )
2346  {
2347  BObject nlines_ob( book->call_custom_method( "getnumlines" ) );
2348  int nlines;
2349  if ( nlines_ob.isa( BObjectImp::OTLong ) )
2350  {
2351  BLong* blong = static_cast<BLong*>( nlines_ob.impptr() );
2352  nlines = blong->value();
2353  }
2354  else
2355  {
2356  return;
2357  }
2358 
2360  msgOut->offset += 2;
2361  msgOut->Write<u32>( book->serial_ext );
2362  msgOut->WriteFlipped<u16>( 1u );
2363 
2364  int linenum = ( page - 1 ) * 8 + 1;
2365 
2366  msgOut->WriteFlipped<u16>( page );
2367  u16 offset = msgOut->offset;
2368  msgOut->offset += 2;
2369 
2370  int pagelines;
2371  for ( pagelines = 0; pagelines < 8 && linenum <= nlines; ++pagelines, ++linenum )
2372  {
2373  std::string linetext;
2374 
2375  BObjectImpRefVec params;
2376  params.push_back( ref_ptr<BObjectImp>( new BLong( linenum ) ) );
2377  BObject line_ob = book->call_custom_method( "getline", params );
2378  linetext = line_ob->getStringRep();
2379 
2380  if ( msgOut->offset + linetext.size() + 1 > sizeof msgOut->buffer )
2381  {
2382  return;
2383  }
2384  msgOut->Write( linetext.c_str(), static_cast<u16>( linetext.size() + 1 ) );
2385  }
2386 
2387  u16 len = msgOut->offset;
2388  msgOut->offset = offset;
2389  msgOut->WriteFlipped<u16>( static_cast<u16>( pagelines ) );
2390  msgOut->offset = 1;
2391  msgOut->WriteFlipped<u16>( len );
2392  msgOut.Send( client, len );
2393  }
2394  else
2395  {
2396  size_t msglen = cfBEu16( msg->msglen );
2397  const char* ptext = msg->text;
2398  size_t bytesleft = msglen - offsetof( PKTBI_66, text );
2399  for ( int i = 1; i <= 8; ++i )
2400  {
2401  std::string line;
2402  while ( bytesleft )
2403  {
2404  --bytesleft;
2405  if ( *ptext )
2406  {
2407  line.append( 1, *ptext );
2408  ++ptext;
2409  }
2410  else
2411  {
2412  ++ptext; // skip null terminator
2413  break;
2414  }
2415  }
2416 
2417  BObjectImpRefVec params;
2418  params.push_back( ref_ptr<BObjectImp>( new BLong( ( page - 1 ) * 8 + i ) ) );
2419  params.push_back( ref_ptr<BObjectImp>( new String( line ) ) );
2420 
2421  BObject page_on = book->call_custom_method( "setline", params );
2422  }
2423  }
2424 }
2425 
2426 char strip_ctrl_chars( char c )
2427 {
2428  if ( c < 0x20 )
2429  return 0x20;
2430  else
2431  return c;
2432 }
2433 
2434 void open_book_handler( Client* client, PKTBI_93* msg )
2435 {
2436  // fdump( stdout, msg, sizeof *msg );
2437 
2438  // string title( msg->title, sizeof msg->title );
2439  // string author( msg->author, sizeof msg->author );
2440 
2441  // Dave changed this 12/19 from sizeof msg->title. The protocol defines garbage after the
2442  // terminator for
2443  // the title and author strings, so we were writing this garbage into save files. This caused some
2444  //"No SERIAL property" bugs, because the parser barfed on the bad characters.
2445  std::string title( msg->title, strlen( msg->title ) );
2446  std::string author( msg->author, strlen( msg->author ) );
2447 
2448  // dave 1/20/3 cheaters insert cntrl chars into books causing severe problems
2449  std::transform( title.begin(), title.end(), title.begin(), strip_ctrl_chars );
2450  std::transform( author.begin(), author.end(), author.begin(), strip_ctrl_chars );
2451 
2452 
2453  unsigned int book_serial = cfBEu32( msg->serial );
2454  Item* book = find_legal_item( client->chr, book_serial );
2455  if ( book == nullptr )
2456  {
2457  POLLOG.Format( "Unable to find book 0x{:X} for character 0x{:X}\n" )
2458  << book_serial << client->chr->serial;
2459  return;
2460  }
2461  BObjectImpRefVec params;
2462  params.push_back( ref_ptr<BObjectImp>( new String( title ) ) );
2463  book->call_custom_method( "settitle", params );
2464 
2465  params[0].set( new String( author ) );
2466  book->call_custom_method( "setauthor", params );
2467 }
2468 
2470 {
2471  Character* chr;
2472  Multi::UMulti* multi;
2473 
2474  if ( !( getCharacterParam( exec, 0, chr ) && getMultiParam( exec, 1, multi ) ) )
2475  {
2476  return new BError( "Invalid parameter type" );
2477  }
2478  if ( ( chr->client->UOExpansionFlag & AOS ) == 0 )
2479  return new BError( "Charater does not have AOS enabled." );
2480 
2481  if ( multi == nullptr )
2482  return new BError( "House not found." );
2483 
2484  Multi::UHouse* house = multi->as_house();
2485  if ( house == nullptr )
2486  return new BError( "Not a House multi." );
2487 
2488  if ( !house->IsCustom() )
2489  return new BError( "Not a Custom House." );
2490 
2491  if ( house->editing )
2492  return new BError( "House currently being customized." );
2493 
2494  if ( house->IsWaitingForAccept() )
2495  return new BError( "House currently being waiting for a commit" );
2496 
2497  if ( chr->realm->find_supporting_multi( chr->x, chr->y, chr->z ) != house )
2498  return new BError( "You must be inside the house to customize it." );
2499 
2500  chr->client->gd->custom_house_serial = house->serial;
2501 
2502  {
2504  msg->WriteFlipped<u16>( 17u );
2505  msg->offset += 2; // sub
2506  msg->Write<u32>( house->serial_ext );
2507  msg->Write<u8>( 0x4u ); // begin
2508  msg->offset += 2; // u16 unk2 FIXME what's the meaning
2509  msg->Write<u32>( 0xFFFFFFFFu ); // fixme
2510  msg->Write<u8>( 0xFFu ); // fixme
2511  msg.Send( chr->client );
2512  }
2513  move_character_to( chr, house->x, house->y, house->z + 7, MOVEITEM_FORCELOCATION, nullptr );
2514  // chr->set_script_member("hidden",1);
2515  // chr->set_script_member("frozen",1);
2516 
2517  house->WorkingDesign.AddComponents( house );
2518  house->CurrentDesign.AddComponents( house );
2520  Multi::ItemList itemlist;
2521  Multi::MobileList moblist;
2522  Multi::UHouse::list_contents( house, itemlist, moblist );
2523  const Multi::MultiDef& def = house->multidef();
2524  while ( !itemlist.empty() )
2525  {
2526  Item* item = itemlist.front();
2527  send_remove_object_if_inrange( chr->client, item );
2528  itemlist.pop_front();
2529  }
2530 
2531  while ( !moblist.empty() )
2532  {
2533  Character* multichr = moblist.back();
2534  if ( multichr != chr )
2535  move_character_to( multichr, house->x + def.minrx, house->y + def.maxry + 1, house->z,
2536  MOVEITEM_FORCELOCATION, nullptr );
2537  moblist.pop_back();
2538  }
2539 
2540  house->editing = true;
2541  house->editing_floor_num = 1;
2543 
2544  return new BLong( 1 );
2545 }
2546 
2548 {
2549  Character* chr;
2550  if ( getCharacterParam( exec, 0, chr ) )
2551  {
2553  msg->WriteFlipped<u16>( 7u );
2554  msg->offset += 2; // sub
2555  msg->Write<u8>( chr->gender );
2556  msg->Write<u8>( chr->race + 1u );
2557  msg.Send( chr->client );
2558  return new BLong( 1 );
2559  }
2560  else
2561  return new BError( "Invalid parameter" );
2562 }
2563 
2564 
2566 {
2567  Item* tmpitem;
2568 
2569  if ( msg->msglen == ctBEu16( 5 ) )
2570  return;
2571 
2572  if ( ( msg->characterracechanger.result.BodyHue == 0 ) &&
2573  ( msg->characterracechanger.result.HairId == 0 ) &&
2574  ( msg->characterracechanger.result.HairHue == 0 ) &&
2575  ( msg->characterracechanger.result.BeardId == 0 ) &&
2576  ( msg->characterracechanger.result.BeardHue == 0 ) )
2577  return;
2578 
2579  client->chr->setcolor( cfBEu16( msg->characterracechanger.result.BodyHue ) | 0x8000 );
2580  client->chr->truecolor = client->chr->color;
2581 
2582  client->chr->on_color_changed();
2583 
2584  // Create Hair
2585  if ( client->chr->layer_is_equipped( LAYER_HAIR ) )
2586  destroy_item( client->chr->wornitem( LAYER_HAIR ) );
2587 
2589  {
2590  tmpitem = Item::create( cfBEu16( msg->characterracechanger.result.HairId ) );
2591  tmpitem->layer = LAYER_HAIR;
2592  tmpitem->color = cfBEu16( msg->characterracechanger.result.HairHue );
2593  tmpitem->realm = client->chr->realm;
2594  client->chr->equip( tmpitem );
2595  send_wornitem_to_inrange( client->chr, tmpitem );
2596  }
2597 
2598  // Create Beard
2599  if ( client->chr->layer_is_equipped( LAYER_BEARD ) )
2600  destroy_item( client->chr->wornitem( LAYER_BEARD ) );
2601 
2603  {
2605  tmpitem->layer = LAYER_BEARD;
2606  tmpitem->color = cfBEu16( msg->characterracechanger.result.BeardHue );
2607  tmpitem->realm = client->chr->realm;
2608  client->chr->equip( tmpitem );
2609  send_wornitem_to_inrange( client->chr, tmpitem );
2610  }
2611 }
2612 
2613 // Called when selection made or when selection canceled with nullptr parameters
2615 {
2616  if ( client == nullptr )
2617  return;
2618 
2619  Character* chr = client->chr;
2620  if ( chr == nullptr || chr->client->gd->popup_menu_selection_uoemod == nullptr )
2621  return;
2622 
2623  // The function sending the PopUp menu is responsible to set this
2626  "Bug in handling PopUp menu selection. Please report this on the forums." );
2627 
2628  if ( id && serial )
2629  {
2631  serial )
2633  new BObject( new BLong( id ) ) );
2634  else
2635  POLLOG_INFO.Format( "{}/{} send an unexpected popup reply for {}.\n" )
2636  << client->acct->name() << client->chr->name() << serial;
2637  }
2638 
2642  chr->client->gd->popup_menu_selection_uoemod = nullptr;
2643 }
2644 
2647 {
2648  Character* chr;
2649  UObject* above;
2650  ObjArray* menu_arr;
2651  if ( !( getCharacterParam( exec, 0, chr ) && getUObjectParam( exec, 1, above ) &&
2652  exec.getObjArrayParam( 2, menu_arr ) ) )
2653  {
2654  return new BError( "Invalid parameter" );
2655  }
2656  if ( !chr->has_active_client() )
2657  return new BError( "No client attached" );
2658  if ( !menu_arr->ref_arr.size() )
2659  return new BError( "Can't send empty menu" );
2660  if ( menu_arr->ref_arr.size() > 0xfffe )
2661  return new BError( "Too many entries in menu" );
2662 
2663  // Prepare packet
2664  // TODO: add KR support?
2666  msg->offset += 4;
2667  msg->Write<u8>( 0u ); // unknown
2668  msg->Write<u8>( 1u ); // 1=2D, 2=KR
2669  msg->Write<u32>( above->serial_ext ); // Above serial
2670  u16 offset_num_entries = msg->offset;
2671  msg->offset += 1; // Skip num entries now, write it later
2672 
2673  u8 num_entries = 0;
2674  for ( u16 i = 0; i < menu_arr->ref_arr.size(); ++i )
2675  {
2676  BObject* bo = menu_arr->ref_arr[i].get();
2677  if ( bo == nullptr )
2678  continue;
2679  BObjectImp* imp = bo->impptr();
2680 
2681  if ( !++num_entries ) // overflow
2682  return new BError( "Too many entries in menu" );
2683 
2684  int cliloc;
2685  bool disabled = false;
2686  bool arrow = false;
2687  u16 color = 0;
2688  bool use_color = false;
2689  if ( imp->isa( BObjectImp::OTLong ) )
2690  {
2691  // Short form: meu is just an int
2692  const BLong* lng = static_cast<BLong*>( imp );
2693  cliloc = lng->value();
2694  }
2695  else if ( imp->isa( BObjectImp::OTStruct ) )
2696  {
2697  // Full form: menu is a struct
2698  BStruct* elem = static_cast<BStruct*>( imp );
2699 
2700  BObjectImp* cl = const_cast<BObjectImp*>( elem->FindMember( "cliloc" ) );
2701  if ( cl == nullptr )
2702  return new BError( "Missing cliloc for menu element" );
2703  if ( !cl->isa( BObjectImp::OTLong ) )
2704  return new BError( "Invalid cliloc for menu element" );
2705  const BLong* lng = static_cast<BLong*>( cl );
2706  cliloc = lng->value();
2707 
2708  const BObjectImp* ds = elem->FindMember( "disabled" );
2709  if ( ds != nullptr )
2710  disabled = ds->isTrue();
2711 
2712  const BObjectImp* ar = elem->FindMember( "arrow" );
2713  if ( ar != nullptr )
2714  arrow = ar->isTrue();
2715 
2716  BObjectImp* co = const_cast<BObjectImp*>( elem->FindMember( "color" ) );
2717  if ( co != nullptr && co->isa( BObjectImp::OTLong ) )
2718  {
2719  const BLong* colng = static_cast<BLong*>( co );
2720  color = static_cast<u16>( colng->value() );
2721  use_color = true;
2722  }
2723  }
2724  else
2725  return new BError( "Menu elements must be int or struct" );
2726 
2727  if ( cliloc < 3000000 || cliloc > 3065535 )
2728  return new BError( "Cliloc out of range in menu" );
2729 
2730  u16 flags = 0x00;
2731  if ( disabled )
2732  flags |= 0x01;
2733  if ( arrow )
2734  flags |= 0x02;
2735  if ( use_color )
2736  flags |= 0x20;
2737  msg->WriteFlipped<u16>( static_cast<u16>( i + 1 ) ); // Menu element ID
2738  msg->WriteFlipped<u16>( static_cast<u16>( cliloc - 3000000 ) ); // Cliloc ID, adjusted
2739  msg->WriteFlipped<u16>( flags ); // Flags
2740  if ( use_color )
2741  msg->WriteFlipped<u16>( static_cast<u16>( color ) );
2742  }
2743 
2744  // Add lengths and send
2745  u16 len = msg->offset;
2746  msg->offset = offset_num_entries;
2747  msg->Write<u8>( num_entries );
2748  msg->offset = 1;
2749  msg->WriteFlipped<u16>( len );
2750  msg.Send( chr->client, len );
2751 
2752  // Cancel any previously waiting popup response
2753  if ( chr->client->gd->popup_menu_selection_uoemod != nullptr )
2754  {
2756 
2757  chr->client->gd->popup_menu_selection_uoemod = nullptr;
2758  chr->on_popup_menu_selection = nullptr;
2759  }
2760 
2761  // Suspend the script first
2762  if ( !uoexec.suspend() )
2763  {
2764  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << exec.PC << ": \n"
2765  << "\tCall to function UO::SendPopupMenu():\n"
2766  << "\tThe execution of this script can't be blocked!\n";
2767  return new Bscript::BError( "Script can't be blocked" );
2768  }
2769 
2770  // Prepare to restart the script once the response arrives
2772  chr->client->gd->popup_menu_selection_uoemod = this;
2773  popup_menu_selection_chr = chr;
2774  popup_menu_selection_above = above;
2775 
2776  return new BLong( 0 );
2777 }
2778 
2780 {
2781  Character* chr = nullptr;
2782  UObject* what = nullptr;
2783 
2784  if ( !getCharacterParam( exec, 0, chr ) || !getUObjectParam( exec, 1, what ) )
2785  return new BError( "Invalid parameter" );
2786 
2787  if ( !chr->has_active_client() )
2788  return new BError( "Mobile has no active client" );
2789 
2790  // If it got here, clear any errors from getUObjectParam/getCharacterParam
2791  exec.setFunctionResult( nullptr );
2792 
2793  singleclick( chr->client, what->serial );
2794  return new BLong( 1 );
2795 }
2796 
2798  /* x, y, z, range, objtype, flags, realm */ )
2799 {
2800  unsigned short x, y;
2801  int z, flags;
2802  short range;
2803  unsigned int objtype;
2804  const String* strrealm;
2805  Realms::Realm* realm;
2806 
2807  if ( getParam( 0, x ) && getParam( 1, y ) && getParam( 2, z ) && getParam( 3, range ) &&
2808  getObjtypeParam( exec, 4, objtype ) && getParam( 5, flags ) &&
2809  getStringParam( 6, strrealm ) )
2810  {
2811  realm = find_realm( strrealm->value() );
2812  if ( !realm )
2813  return new BError( "Realm not found" );
2814 
2815  if ( z == LIST_IGNORE_Z )
2816  {
2817  if ( !realm->valid( x, y, 0 ) )
2818  return new BError( "Invalid Coordinates for realm" );
2819  }
2820  else
2821  {
2822  if ( !realm->valid( x, y, static_cast<short>( z ) ) )
2823  return new BError( "Invalid Coordinates for realm" );
2824  }
2825 
2826  std::unique_ptr<ObjArray> newarr( new ObjArray );
2827 
2828  short wxL, wyL, wxH, wyH;
2829  wxL = x - range;
2830  if ( wxL < 0 )
2831  wxL = 0;
2832  wyL = y - range;
2833  if ( wyL < 0 )
2834  wyL = 0;
2835  wxH = x + range;
2836  if ( wxH > realm->width() - 1 )
2837  wxH = realm->width() - 1;
2838  wyH = y + range;
2839  if ( wyH > realm->height() - 1 )
2840  wyH = realm->height() - 1;
2841 
2842  for ( unsigned short wx = wxL; wx <= wxH; ++wx )
2843  {
2844  for ( unsigned short wy = wyL; wy <= wyH; ++wy )
2845  {
2846  if ( !( flags & ITEMS_IGNORE_STATICS ) )
2847  {
2848  Plib::StaticEntryList slist;
2849  realm->getstatics( slist, wx, wy );
2850 
2851  for ( unsigned i = 0; i < slist.size(); ++i )
2852  {
2853  if ( slist[i].objtype != objtype )
2854  continue;
2855  if ( ( z == LIST_IGNORE_Z ) || ( abs( slist[i].z - z ) < CONST_DEFAULT_ZRANGE ) )
2856  {
2857  std::unique_ptr<BStruct> arr( new BStruct );
2858  arr->addMember( "x", new BLong( wx ) );
2859  arr->addMember( "y", new BLong( wy ) );
2860  arr->addMember( "z", new BLong( slist[i].z ) );
2861  arr->addMember( "objtype", new BLong( slist[i].objtype ) );
2862  arr->addMember( "hue", new BLong( slist[i].hue ) );
2863  newarr->addElement( arr.release() );
2864  }
2865  }
2866  }
2867 
2868  if ( !( flags & ITEMS_IGNORE_MULTIS ) )
2869  {
2870  StaticList mlist;
2871  realm->readmultis( mlist, wx, wy );
2872  for ( unsigned i = 0; i < mlist.size(); ++i )
2873  {
2874  if ( mlist[i].graphic != objtype )
2875  continue;
2876  if ( ( z == LIST_IGNORE_Z ) || ( abs( mlist[i].z - z ) < CONST_DEFAULT_ZRANGE ) )
2877  {
2878  std::unique_ptr<BStruct> arr( new BStruct );
2879  arr->addMember( "x", new BLong( wx ) );
2880  arr->addMember( "y", new BLong( wy ) );
2881  arr->addMember( "z", new BLong( mlist[i].z ) );
2882  arr->addMember( "objtype", new BLong( mlist[i].graphic ) );
2883  newarr->addElement( arr.release() );
2884  }
2885  }
2886  }
2887  }
2888  }
2889 
2890  return newarr.release();
2891  }
2892  else
2893  return new BError( "Invalid parameter" );
2894 }
2895 
2896 
2898  /* x, y, z, range, flags, realm */ )
2899 {
2900  unsigned short x, y;
2901  int z, flags;
2902  short range;
2903  const String* strrealm;
2904  Realms::Realm* realm;
2905 
2906  if ( getParam( 0, x ) && getParam( 1, y ) && getParam( 2, z ) && getParam( 3, range ) &&
2907  getParam( 4, flags ) && getStringParam( 5, strrealm ) )
2908  {
2909  realm = find_realm( strrealm->value() );
2910  if ( !realm )
2911  return new BError( "Realm not found" );
2912 
2913  if ( z == LIST_IGNORE_Z )
2914  {
2915  if ( !realm->valid( x, y, 0 ) )
2916  return new BError( "Invalid Coordinates for realm" );
2917  }
2918  else
2919  {
2920  if ( !realm->valid( x, y, static_cast<short>( z ) ) )
2921  return new BError( "Invalid Coordinates for realm" );
2922  }
2923 
2924  std::unique_ptr<ObjArray> newarr( new ObjArray );
2925 
2926  short wxL, wyL, wxH, wyH;
2927  wxL = x - range;
2928  if ( wxL < 0 )
2929  wxL = 0;
2930  wyL = y - range;
2931  if ( wyL < 0 )
2932  wyL = 0;
2933  wxH = x + range;
2934  if ( wxH > realm->width() - 1 )
2935  wxH = realm->width() - 1;
2936  wyH = y + range;
2937  if ( wyH > realm->height() - 1 )
2938  wyH = realm->height() - 1;
2939 
2940  for ( unsigned short wx = wxL; wx <= wxH; ++wx )
2941  {
2942  for ( unsigned short wy = wyL; wy <= wyH; ++wy )
2943  {
2944  if ( !( flags & ITEMS_IGNORE_STATICS ) )
2945  {
2946  Plib::StaticEntryList slist;
2947  realm->getstatics( slist, wx, wy );
2948 
2949  for ( unsigned i = 0; i < slist.size(); ++i )
2950  {
2951  if ( ( tile_uoflags( slist[i].objtype ) & flags ) )
2952  {
2953  if ( ( z == LIST_IGNORE_Z ) || ( abs( slist[i].z - z ) < CONST_DEFAULT_ZRANGE ) )
2954  {
2955  std::unique_ptr<BStruct> arr( new BStruct );
2956  arr->addMember( "x", new BLong( wx ) );
2957  arr->addMember( "y", new BLong( wy ) );
2958  arr->addMember( "z", new BLong( slist[i].z ) );
2959  arr->addMember( "objtype", new BLong( slist[i].objtype ) );
2960  arr->addMember( "hue", new BLong( slist[i].hue ) );
2961  newarr->addElement( arr.release() );
2962  }
2963  }
2964  }
2965  }
2966 
2967  if ( !( flags & ITEMS_IGNORE_MULTIS ) )
2968  {
2969  StaticList mlist;
2970  realm->readmultis( mlist, wx, wy );
2971  for ( unsigned i = 0; i < mlist.size(); ++i )
2972  {
2973  if ( ( tile_uoflags( mlist[i].graphic ) & flags ) )
2974  {
2975  if ( ( z == LIST_IGNORE_Z ) || ( abs( mlist[i].z - z ) < CONST_DEFAULT_ZRANGE ) )
2976  {
2977  std::unique_ptr<BStruct> arr( new BStruct );
2978  arr->addMember( "x", new BLong( wx ) );
2979  arr->addMember( "y", new BLong( wy ) );
2980  arr->addMember( "z", new BLong( mlist[i].z ) );
2981  arr->addMember( "objtype", new BLong( mlist[i].graphic ) );
2982  newarr->addElement( arr.release() );
2983  }
2984  }
2985  }
2986  }
2987  }
2988  }
2989 
2990  return newarr.release();
2991  }
2992  else
2993  return new BError( "Invalid parameter" );
2994 }
2995 } // namespace Module
2996 } // namespace Pol
virtual void on_insert_add_item(Mobile::Character *mob, MoveType move, Items::Item *new_item)
Definition: containr.cpp:833
#define LAYER_VENDOR_PLAYER_ITEMS
Definition: pktdef.h:22
unsigned char u8
Definition: rawtypes.h:25
bool newbie() const
Definition: item.h:338
std::unique_ptr< Network::PacketsSingleton > packetsSingleton
Definition: network.h:95
u16 wyH
Definition: uworld.h:181
Module::UOExecutorModule * popup_menu_selection_uoemod
Definition: cgdata.h:63
const int VENDOR_SEND_AOS_TOOLTIP
Definition: core.h:72
static Item * create(u32 objtype, u32 serial=0)
Definition: itemcr.cpp:53
CustomHouseDesign WorkingDesign
Definition: house.h:79
void send_clear_vendorwindow(Client *client, Character *vendor)
Definition: uomod2.cpp:323
AccountsVector accounts
Definition: uvars.h:144
#define CONST_DEFAULT_ZRANGE
Definition: uomod2.cpp:128
Bscript::BObjectImp * mf_FindAccount()
Definition: uomod2.cpp:2064
Clib::fixed_allocator< sizeof(Double), 256 > double_alloc
Definition: object.cpp:45
int get_toplevel_item_count()
Definition: uworld.cpp:109
std::map< u8, PacketQueue * > PacketQueueMap
std::atomic< u64 > bytes_sent
Definition: polstats.h:21
std::set< UOExecutor * > NoTimeoutHoldList
#define POL_OVERRIDE
size_t getCurrentMemoryUsage()
returns the current process size in bytes
Definition: xmain.cpp:26
const ExecList & getRanlist()
virtual std::string getStringRep() const =0
const int ITEMS_IGNORE_STATICS
Definition: core.h:64
ref_ptr< Core::UContainer > vendor_for_sale
Definition: cgdata.h:43
const std::string & value() const
Definition: impstr.h:67
u16 tag
Definition: pktin.h:429
const int LIST_IGNORE_Z
Definition: core.h:67
virtual Bscript::BObjectImp * make_ref() POL_OVERRIDE
Definition: uoscrobj.cpp:1628
std::list< Items::Item * > ItemList
Definition: house.h:60
bool send_vendorwindow_contents(Network::Client *client, Core::UContainer *for_sale, bool send_aos_tooltip)
Definition: uomod2.cpp:173
BObjectType type() const
Definition: bobject.h:358
int value() const
Definition: bobject.h:592
virtual bool can_add(const Items::Item &item) const
Definition: containr.cpp:168
void singleclick(Network::Client *client, u32 serial)
Definition: sngclick.cpp:92
virtual BObjectRef get_member(const char *membername) POL_OVERRIDE
Definition: uomod2.cpp:1921
bool stackable() const
Definition: item.cpp:570
Account * create_new_account(const std::string &acctname, const std::string &password, bool enabled)
Definition: accounts.cpp:109
std::vector< StaticRec > StaticList
Definition: udatfile.h:38
ValueStackCont ValueStack
Definition: executor.h:120
const int VENDOR_BUYABLE_CONTAINER_FILTER
Definition: core.h:73
char strip_ctrl_chars(char c)
Definition: uomod2.cpp:2426
bool send_event(Bscript::BObjectImp *event)
Definition: npc.cpp:887
void open_book_handler(Client *client, PKTBI_93 *msg)
Definition: uomod2.cpp:2434
Bscript::BObjectImp * mf_CreateAccount()
Definition: uomod2.cpp:2029
static void list_contents(const UHouse *house, ItemList &items_in, MobileList &chrs_in)
Definition: house.cpp:63
int get_mobile_count()
Definition: uworld.cpp:117
SystemState systemstate
Definition: systemstate.cpp:12
bool isa(BObjectType type) const
Definition: bobject.h:353
Network::Client * client
Definition: charactr.h:871
Mobile::Character * gump_chr
Definition: uomod.h:304
polclock_t polclock()
Definition: polclock.cpp:72
unsigned int tile_uoflags(unsigned short tilenum)
Definition: polfile2.cpp:61
u16 wyL
Definition: uworld.h:179
Accounts::Account * acct
Definition: client.h:181
void log_all_script_cycle_counts(bool clear_counters)
Definition: scrstore.cpp:157
void add_script(ObjArray *arr, UOExecutor *uoexec, const char *)
Definition: uomod2.cpp:1711
const HoldList & getHoldlist()
Module::UOExecutorModule * textentry_uoemod
Definition: cgdata.h:53
bool getbuyprice(u32 &buyprice) const
Definition: item.cpp:227
Packet received[256]
Definition: iostats.h:26
const int SENDDIALOGMENU_FORCE_OLD
Definition: core.h:75
#define cfBEu32(x)
Definition: clib_endian.h:43
T * get() const
Definition: refptr.h:176
std::tm localtime(const std::time_t &t)
threadsafe version of localtime
Definition: clib.h:143
#define POLLOG_INFO
Definition: logfacility.h:213
Core::UOExecutor & uoexec
Definition: uomod.h:291
std::string decint(unsigned short v)
Definition: strutil.cpp:64
Bscript::BObjectImp * mf_SendOpenBook()
Definition: uomod2.cpp:2203
virtual void on_color_changed() POL_OVERRIDE
Definition: charactr.cpp:1676
bool move_character_to(Mobile::Character *chr, unsigned short x, unsigned short y, short z, int flags, Realms::Realm *oldrealm)
Definition: core.cpp:50
const unsigned VALID_ITEM_COLOR_MASK
Definition: uconst.h:76
Items::Item * find(u32 serial) const
Definition: containr.cpp:620
unsigned int calculate_cost(Character *, UContainer *for_sale, UContainer *bought, PKTBI_3B *msg)
Definition: uomod2.cpp:331
void clear_script_profile_counters()
Definition: scrstore.cpp:202
std::string merchant_description() const
Definition: item.cpp:177
#define ctBEu16(x)
Definition: clib_endian.h:46
bool has_active_client() const
Definition: charactr.cpp:448
void gumpbutton_handler(Client *client, PKTIN_B1 *msg)
Definition: uomod2.cpp:1421
std::list< Mobile::Character * > MobileList
Definition: house.h:61
Bscript::BObjectImp * mf_SendGumpMenu()
Definition: uomod2.cpp:954
boost_utils::script_name_flystring name
Definition: eprog.h:91
Item * find_legal_item(const Character *chr, u32 serial, bool *additlegal, bool *isRemoteContainer)
Definition: ufunc.cpp:958
virtual BObjectImp * copy() const =0
Mobile::Character * resurrect_chr
Definition: uomod.h:306
Bscript::BObjectImp * mf_SingleClick()
Definition: uomod2.cpp:2779
std::map< u16, PacketInterfaceQueue > PacketInterfaceQueueMap
u64 pid
Definition: osmod.cpp:945
u8 data[1]
Definition: pktin.h:431
CustomHouseDesign CurrentDesign
Definition: house.h:78
Packet sent[256]
Definition: iostats.h:25
Definition: pktin.h:419
virtual u8 typeOfInt() const
Definition: object.cpp:263
BObjectImp * GetScriptProfiles()
Definition: uomod2.cpp:1762
Definition: pktin.h:427
Contents::iterator iterator
Definition: containr.h:114
virtual std::string getStringRep() const POL_OVERRIDE
Definition: uomod2.cpp:1283
#define POLLOG_ERROR
Definition: logfacility.h:207
const std::string & name() const
Definition: pkg.h:83
bool isa(BObjectImp::BObjectType type) const
Definition: bobject.h:423
Bscript::BObjectImp * mf_SendCharacterRaceChanger()
Definition: uomod2.cpp:2547
void send_remove_object_if_inrange(Client *client, const Item *item)
Definition: ufunc.cpp:409
#define UOBJ_GOLD_COIN
Definition: objtype.h:209
const ExecList & getRunlist()
void(* on_popup_menu_selection)(Network::Client *client, u32 serial, u16 id)
Definition: charactr.h:864
Bscript::BObject call_custom_method(const char *methodname, Bscript::BObjectImpRefVec &pmore)
Definition: uoscrobj.cpp:1605
const ItemDesc & find_itemdesc(unsigned int objtype)
Definition: itemdesc.cpp:933
PKTBI_BF_RACE_CHANGER_RESULT characterracechanger
Definition: pktboth.h:874
void clear_gumphandler(Client *client, UOExecutorModule *uoemod)
Definition: uomod2.cpp:1339
Bscript::BObjectImp * mf_PolCore()
Definition: uomod2.cpp:2017
Clib::fixed_allocator< sizeof(BLong), 256 > blong_alloc
Definition: object.cpp:44
Bscript::BObjectImp * mf_SelectColor()
Definition: uomod2.cpp:2170
void add_to_self(Item *&item)
Definition: item.cpp:600
void AddComponents(UHouse *house)
ProfileVars profilevars
Definition: state.h:47
virtual void add(Items::Item *item)
Definition: containr.cpp:194
virtual bool script_isa(unsigned isatype) const
Definition: uoscrobj.cpp:4566
BIntHash & operator=(const BIntHash &)
Mobile::Character * chr
Definition: client.h:182
void PrintHeapData()
Definition: opnew.cpp:440
virtual Items::Item * remove(u32 serial, UContainer **found_in=nullptr)
Definition: containr.cpp:510
Core::UGENDER gender
Definition: charactr.h:918
char data[1]
Definition: pktin.h:389
Module::UOExecutorModule * find_gumpmod(u32 gumpid)
Given a gumpid, finds the module that registered it, returns nullptr if not found.
Definition: cgdata.cpp:149
Items::Item * find_addable_stack(const Items::Item *adding_item) const
Definition: containr.cpp:403
unsigned short u16
Definition: rawtypes.h:26
unsigned char buffer[10000]
Definition: UoToolMain.cpp:109
void oldSellHandler(Client *client, PKTIN_9F *msg)
Definition: uomod2.cpp:777
unsigned int u32
Definition: rawtypes.h:27
void get_random_location(u16 *px, u16 *py) const
Definition: containr.cpp:712
bool getCharacterParam(Bscript::Executor &exec, unsigned param, Mobile::Character *&chrptr)
Definition: uoexhelp.cpp:140
const u16 AOS
Definition: client.h:75
void clear()
Definition: refptr.h:283
unsigned long long u64
Definition: rawtypes.h:38
virtual size_t sizeEstimate() const POL_OVERRIDE
Definition: uomod2.cpp:1669
void spend_gold(unsigned int amount)
Definition: charactr.cpp:1321
#define LEAKLOG
Definition: logfacility.h:241
virtual std::string getStringRep() const POL_OVERRIDE
Definition: uomod2.cpp:1685
#define RESURRECT_CHOICE_SELECT
Definition: pktdef.h:87
#define LAYER_VENDOR_FOR_SALE
Definition: pktdef.h:21
virtual size_t sizeEstimate() const POL_OVERRIDE
Definition: uomod2.cpp:1271
void setimp(BObjectImp *imp)
Definition: bobject.h:446
Bscript::BObjectImp * mf_SendBuyWindow()
Definition: uomod2.cpp:208
BObjectImp * GetAllScriptList()
Definition: uomod2.cpp:1734
#define DEBUGLOG
Definition: logfacility.h:237
virtual class UHouse * as_house()
Definition: multis.cpp:55
void destroy_item(Item *item)
Definition: ufunc.cpp:1538
virtual bool isTrue() const
Definition: object.cpp:911
const BObjectImp * imp_at(unsigned index) const
Definition: object.cpp:1100
std::atomic< u64 > bytes_received
Definition: polstats.h:20
u16 wxH
Definition: uworld.h:180
Bscript::BObjectImp * mf_ListStaticsNearLocationWithFlag()
Definition: uomod2.cpp:2897
void add(int key, BObjectImp *value)
Definition: uomod2.cpp:1288
Clib::fixed_allocator< sizeof(UninitObject), 256 > uninit_alloc
Definition: object.cpp:43
void sanitize_upperlimit(T *value, const T max)
Definition: clib.h:101
Items::Item * find_toplevel(u32 serial) const
Definition: containr.cpp:645
Definition: refptr.h:65
NetworkManager networkManager
Definition: network.cpp:28
std::multimap< Core::polclock_t, Core::UOExecutor * > HoldList
Module::UOExecutorModule * selcolor_uoemod
Definition: cgdata.h:66
unsigned short height() const
Definition: realm.h:245
void Send(Client *client, int len=-1) const
Definition: packethelper.h:69
bool scripted_merchant_handlers
Definition: ssopt.h:84
BObjectImp * GetIoStats()
Definition: uomod2.cpp:1822
const char * name() const
Definition: account.cpp:193
Bscript::BObjectImp * mf_SendSellWindow()
Definition: uomod2.cpp:691
#define GET_PROFILEVAR_PER_MIN(counter)
Definition: profile.h:100
std::deque< UOExecutor * > ExecList
Module::UOExecutorModule * resurrect_uoemod
Definition: cgdata.h:65
void SendAOSTooltip(Network::Client *client, UObject *obj, bool vendor_content)
Definition: tooltips.cpp:93
void getstatics(Plib::StaticEntryList &statics, unsigned short x, unsigned short y) const
Definition: realmfunc.cpp:752
bool orphan() const
Definition: baseobject.h:119
const unsigned POLCLASS_CONTAINER
Definition: polclass.h:18
Bscript::BObjectImp * mf_CloseWindow()
Definition: uomod2.cpp:1383
static UninitObject * create()
Definition: bobject.h:482
Bscript::BObjectImp * mf_SendHousingTool()
Definition: uomod2.cpp:2469
Bscript::BObjectImp * internal_SendCompressedGumpMenu(Mobile::Character *chr, Bscript::ObjArray *layout_arr, Bscript::ObjArray *data_arr, int x, int y, u32 gumpid)
Definition: uomod2.cpp:1114
char title[60]
Definition: pktboth.h:418
bool IsCustom() const
Definition: house.h:84
virtual BObjectImp * copy() const POL_OVERRIDE
Definition: uomod2.cpp:1266
struct Pol::Core::PKTBI_3B::@19 items[1]
signed int s32
Definition: rawtypes.h:31
Bscript::BObjectImp * mf_ListStaticsNearLocationOfType()
Definition: uomod2.cpp:2797
void on_insert_increase_stack(Mobile::Character *mob, MoveType move, Items::Item *existing_item, unsigned short amt_added)
Definition: containr.cpp:805
BObjectImp * _create_item_in_container(UContainer *cont, const ItemDesc *descriptor, unsigned short amount, bool force_stacking, UOExecutorModule *uoemod)
Definition: uomod.cpp:339
size_t numParams() const
Definition: executor.h:145
Bscript::BObjectImp * mf_ListAccounts()
Definition: uomod2.cpp:2085
#define cfBEu16(x)
Definition: clib_endian.h:44
u32 sellprice() const
Definition: item.cpp:198
#define POLLOG
Definition: logfacility.h:219
bool getItemParam(Executor &exec, unsigned param, Items::Item *&itemptr)
Definition: uoexhelp.cpp:219
struct Pol::Core::PKTIN_9F::@52 items[1]
BObjectImp * GetIoStatsObj(const IOStats &stats)
Definition: uomod2.cpp:1793
bool validhair(u16 HairStyle)
Definition: create.cpp:117
void add_at_random_location(Items::Item *item)
Definition: containr.cpp:291
ClientGameData * gd
Definition: client.h:252
virtual BObjectImp * call_method(const char *methodname, Executor &ex)
Definition: object.cpp:916
const unsigned POLCLASS_MOBILE
Definition: polclass.h:15
unsigned int SafeCharAmt() const
Definition: str.cpp:192
void handle_textentry(Client *client, PKTIN_AC *msg)
Definition: uomod2.cpp:1623
#define GET_ITEM_PTR(itr)
Definition: containr.h:38
const u32 objtype_
Definition: uobject.h:249
Core::URACE race
Definition: charactr.h:919
GameState gamestate
Definition: uvars.cpp:74
void send_full_statmsg(Network::Client *client, Mobile::Character *chr)
Definition: statmsg.cpp:32
Item * remove_part_of_stack(u16 amount_to_remove)
Definition: item.cpp:801
BObjectImp * impptr()
Definition: bobject.h:428
Core::UObject * popup_menu_selection_above
Definition: uomod.h:302
void equip(Items::Item *item)
Definition: charactr.cpp:1433
BObjectImp * GetPktStatusObj()
Definition: uomod2.cpp:1832
bool compareVersion(const std::string &ver)
Definition: client.cpp:340
#define passert_always_r(exp, reason)
Definition: passert.h:84
std::unordered_map< u64, ScriptDiffData > data
Definition: osmod.cpp:966
void send_wornitem(Client *client, const Character *chr, const Item *item)
Definition: ufunc.cpp:825
SettingsManager settingsManager
Definition: settings.cpp:14
void buyhandler(Client *client, PKTBI_3B *msg)
Definition: uomod2.cpp:548
size_t last_sysload_nprocs
Definition: profile.h:63
Mobile::Character * popup_menu_selection_chr
Definition: uomod.h:301
StateManager stateManager
Definition: state.cpp:8
ScriptScheduler scriptScheduler
bool getObjtypeParam(Executor &exec, unsigned param, unsigned int &objtype)
Definition: uoexhelp.cpp:400
const int MOVEITEM_FORCELOCATION
Definition: core.h:52
virtual BObjectRef OperSubscript(const BObject &obj) POL_OVERRIDE
Definition: uomod2.cpp:1316
bool send_vendorsell(Client *client, NPC *merchant, UContainer *sellfrom, UContainer *buyable, bool send_aos_tooltip)
Definition: uomod2.cpp:620
ref_ptr< Items::Item > ItemRef
Definition: reftypes.h:43
void popup_menu_selection_made(Network::Client *client, u32 serial, u16 id)
Definition: uomod2.cpp:2614
void add_gumpmod(Module::UOExecutorModule *, u32 gumpid)
Registers a gumpid for the given module.
Definition: cgdata.cpp:143
u16 getamount() const
Definition: item.h:295
ref_ptr< Core::UContainer > vendor_bought
Definition: cgdata.h:42
const struct VersionDetailStruct CLIENT_VER_5000
Definition: client.h:101
Core::AccountRef acct
Definition: charactr.h:914
int editing_floor_num
Definition: house.h:92
BObjectImp & impref()
Definition: bobject.h:438
void readmultis(Plib::MapShapeList &vec, unsigned short x, unsigned short y, unsigned int flags) const
Definition: realmfunc.cpp:623
ref_ptr< Accounts::Account > AccountRef
Definition: reftypes.h:45
#define LONG_COREVAR(name, expr)
void addElement(BObjectImp *imp)
Definition: object.cpp:1399
const int ITEMS_IGNORE_MULTIS
Definition: core.h:65
Core::UContainer * backpack() const
Definition: charactr.cpp:1276
virtual const char * typeOf() const POL_OVERRIDE
Definition: uomod2.cpp:1690
Bscript::BObjectImp * internal_SendUnCompressedGumpMenu(Mobile::Character *chr, Bscript::ObjArray *layout_arr, Bscript::ObjArray *data_arr, int x, int y, u32 gumpid)
Definition: uomod2.cpp:1009
bool getUObjectParam(Executor &exec, unsigned param, UObject *&objptr)
Definition: uoexhelp.cpp:369
Bscript::BObjectImp * mf_SendPopUpMenu()
Sends a PopUp/Context menu.
Definition: uomod2.cpp:2646
void send_container_contents(Network::Client *client, const UContainer &cont)
Definition: ufunc2.cpp:78
unsigned count() const
Definition: containr.h:267
virtual BObjectImp * call_method(const char *methodname, Executor &ex) POL_OVERRIDE
Definition: uomod2.cpp:1926
Mobile::Character * selcolor_chr
Definition: uomod.h:307
void oldBuyHandler(Client *client, PKTBI_3B *msg)
Definition: uomod2.cpp:354
Realms::Realm * realm
Definition: baseobject.h:56
bool getMultiParam(Executor &exec, unsigned param, Multi::UMulti *&multiptr)
Definition: uoexhelp.cpp:323
virtual u8 typeOfInt() const POL_OVERRIDE
Definition: uomod2.cpp:1694
BObjectImp * GetQueuedIoStats()
Definition: uomod2.cpp:1827
std::atomic< unsigned int > count
Definition: iostats.h:21
std::atomic< unsigned int > bytes
Definition: iostats.h:22
unsigned short width() const
Definition: realm.h:241
u32 value
Definition: pktin.h:421
virtual BObjectImp * copy() const POL_OVERRIDE
Definition: uomod2.cpp:1680
Realms::Realm * find_realm(const std::string &name)
Definition: realms.cpp:64
std::map< int, BObjectRef > Contents
Definition: uomod2.cpp:1255
u16 length
Definition: pktin.h:430
unsigned int gold_carried() const
Definition: charactr.cpp:1309
bool can_insert_increase_stack(Mobile::Character *mob, MoveType move, Items::Item *existing_item, unsigned short amt_to_add, Items::Item *adding_item)
Definition: containr.cpp:787
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
void send_wornitem_to_inrange(const Character *chr, const Item *item)
Definition: ufunc.cpp:842
bool amount_to_remove_is_partial(u16 amount_to_remove) const
Definition: item.cpp:768
bool start_script(Bscript::EScriptProgram *prog, bool start_attached, Bscript::BObjectImp *param2=nullptr, Bscript::BObjectImp *param3=nullptr, Bscript::BObjectImp *param4=nullptr)
Definition: chrituse.cpp:30
Items::Item * wornitem(int layer) const
Definition: charactr.cpp:1332
#define ERROR_PRINT
Definition: logfacility.h:230
const NoTimeoutHoldList & getNoTimeoutHoldlist()
Item * slice_stacked_item(u16 this_item_new_amount)
Definition: item.cpp:790
virtual BObjectRef get_member(const char *membername) POL_OVERRIDE
Definition: uomod2.cpp:1294
bool inuse() const
Definition: item.h:314
char author[30]
Definition: pktboth.h:419
const MultiDef & multidef() const
Definition: multis.cpp:69
void CustomHousesSendFull(UHouse *house, Network::Client *client, int design)
bool valid(unsigned short x, unsigned short y, short z) const
Definition: realm.cpp:119
std::vector< ref_ptr< BObjectImp > > BObjectImpRefVec
Definition: bobject.h:409
void set(T *ptr)
Definition: refptr.h:276
ref_ptr< Bscript::EScriptProgram > find_script(const std::string &name, bool complain_if_not_found, bool cache_script)
Definition: scrstore.cpp:38
void sellhandler(Client *client, PKTIN_9F *msg)
Definition: uomod2.cpp:890
virtual bool setcolor(u16 newcolor)
Definition: uobject.cpp:368
Bscript::BObjectImp * mf_SendTextEntryGump()
Definition: uomod2.cpp:1565
u16 wxL
Definition: uworld.h:178
#define passert_always(exp)
Definition: passert.h:80
#define INFO_PRINT
Definition: logfacility.h:223
void handle_selcolor(Client *client, PKTBI_95 *msg)
Definition: uomod2.cpp:2140
Multi::UMulti * find_supporting_multi(unsigned short x, unsigned short y, short z) const
Definition: realmfunc.cpp:709
virtual std::string name() const
Definition: uobject.cpp:196
bool IsWaitingForAccept() const
Definition: house.h:89
BObjectImp * GetPackageList()
Definition: uomod2.cpp:1699
BObjectImp * GetRunningScriptList()
Definition: uomod2.cpp:1716
#define LAYER_VENDOR_BUYABLE_ITEMS
Definition: pktdef.h:23
Clib::fixed_allocator< sizeof(BObject), 256 > bobject_alloc
Definition: object.cpp:42
BObjectImp * MakeMapCacheImp()
Definition: uomod2.cpp:2022
void remove_gumpmods(Module::UOExecutorModule *)
Removes all the registered gumpids for a given module.
Definition: cgdata.cpp:158
unsigned int invocations
Definition: eprog.h:121
const char * data() const
Definition: impstr.h:66
void read_book_page_handler(Client *client, PKTBI_66 *msg)
Definition: uomod2.cpp:2333
bool layer_is_equipped(int layer) const
Definition: charactr.cpp:1337
Definition: berror.cpp:12
const polclock_t POLCLOCKS_PER_SEC
Definition: polclock.h:29
virtual const char * typeOf() const
Definition: object.cpp:257
const BObjectImp * FindMember(const char *name)
Definition: bstruct.cpp:216
Bscript::BObjectImp * mf_SendInstaResDialog()
Definition: uomod2.cpp:2113
size_t length() const
Definition: impstr.h:68
unsigned int instance_
Definition: client.h:253
void handle_resurrect_menu(Client *client, PKTBI_2C *msg)
Definition: uomod2.cpp:2095
Bscript::BObjectImp * mf_CloseGump()
Definition: uomod2.cpp:1346
Account * find_account(const char *acctname)
Definition: accounts.cpp:151
static void ClearComponents(UHouse *house)
void character_race_changer_handler(Network::Client *client, Core::PKTBI_BF *msg)
Definition: uomod2.cpp:2565
void update_item_to_inrange(const Item *item)
Definition: ufunc.cpp:737
Module::OSExecutorModule * os_module
Definition: uoexec.h:37
static std::string build_datetime()
bool validbeard(u16 BeardStyle)
Definition: create.cpp:153
Mobile::Character * textentry_chr
Definition: uomod.h:305
static const unsigned int PID_MIN
BObjectImp * GetCoreVariable(const char *corevar)
Definition: uomod2.cpp:1860
bool getParam(unsigned param, int &value)
Definition: executor.cpp:363
bool can_insert_add_item(Mobile::Character *mob, MoveType move, Items::Item *new_item)
Definition: containr.cpp:817