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