Pol  Revision:cb584c9
ufunc.cpp
Go to the documentation of this file.
1 
41 #include "ufunc.h"
42 
43 #include <cstddef>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <string>
48 
49 #include "../clib/clib_endian.h"
50 #include "../clib/logfacility.h"
51 #include "../clib/passert.h"
52 #include "../plib/mapcell.h"
53 #include "../plib/systemstate.h"
54 #include "accounts/account.h"
55 #include "containr.h"
56 #include "fnsearch.h"
57 #include "globals/network.h"
58 #include "globals/object_storage.h"
59 #include "globals/state.h"
60 #include "globals/uvars.h"
61 #include "item/item.h"
62 #include "layers.h"
63 #include "lightlvl.h"
64 #include "mdelta.h"
65 #include "miscrgn.h"
66 #include "mobile/charactr.h"
67 #include "mobile/corpse.h"
68 #include "multi/multi.h"
69 #include "multi/multidef.h"
70 #include "network/cgdata.h"
71 #include "network/client.h"
72 #include "network/packetdefs.h"
73 #include "network/packethelper.h"
74 #include "objecthash.h"
75 #include "objtype.h"
76 #include "pktdef.h"
77 #include "polcfg.h"
78 #include "polclass.h"
79 #include "realms/realm.h"
80 #include "statmsg.h"
81 #include "tooltips.h"
82 #include "uobject.h"
83 #include "uoclient.h"
84 #include "uworld.h"
85 
86 namespace Pol
87 {
88 namespace Core
89 {
90 using namespace Network;
91 using namespace Mobile;
92 using namespace Items;
93 
94 // Dave added 3/9/3
96 {
98 }
99 
100 // Dave added 3/9/3
102 {
104 }
105 
106 // Dave added 3/8/3
108 {
110 }
111 
112 // Dave added 3/8/3
114 {
116 }
117 
118 // Dave changed 3/8/3 to use objecthash
120 {
122  stateManager.charserialnumber = nextserial;
124 }
125 
127 {
128  if ( serial > stateManager.charserialnumber )
129  stateManager.charserialnumber = serial + 1;
130  return serial;
131 }
132 
133 // Dave changed 3/8/3
135 {
136  if ( serial > stateManager.itemserialnumber )
137  stateManager.itemserialnumber = serial + 1;
138  return serial;
139 }
140 
141 // Dave changed 3/8/3 to use objecthash
143 {
145  stateManager.itemserialnumber = nextserial;
147 }
148 
149 void send_goxyz( Client* client, const Character* chr )
150 {
152  msg->Write<u32>( chr->serial_ext );
153  msg->WriteFlipped<u16>( chr->graphic );
154  msg->offset++; // unk7
155  msg->WriteFlipped<u16>( chr->color );
156  msg->Write<u8>( chr->get_flag1( client ) );
157  msg->WriteFlipped<u16>( chr->x );
158  msg->WriteFlipped<u16>( chr->y );
159  msg->offset += 2; // unk15,16
160  msg->Write<u8>( 0x80u | chr->facing ); // is it always right to set this flag?
161  msg->Write<s8>( chr->z );
162  msg.Send( client );
163 
164  if ( ( client->ClientType & CLIENTTYPE_UOKR ) &&
165  ( chr->poisoned() ) ) // if poisoned send 0x17 for newer clients
166  send_poisonhealthbar( client, chr );
167 
168  if ( ( client->ClientType & CLIENTTYPE_UOKR ) &&
169  ( chr->invul() ) ) // if invul send 0x17 for newer clients
170  send_invulhealthbar( client, chr );
171 }
172 
173 // Character chr has moved. Tell a client about it.
174 void send_move( Client* client, const Character* chr )
175 {
176  MoveChrPkt msgmove( chr );
177  msgmove.Send( client );
178 
179  if ( chr->poisoned() ) // if poisoned send 0x17 for newer clients
180  send_poisonhealthbar( client, chr );
181 
182  if ( chr->invul() ) // if invul send 0x17 for newer clients
183  send_invulhealthbar( client, chr );
184 }
185 
186 void send_poisonhealthbar( Client* client, const Character* chr )
187 {
188  if ( client->ClientType & Network::CLIENTTYPE_UOKR )
189  {
191  chr->serial_ext, Network::HealthBarStatusUpdate::Color::GREEN, chr->poisoned() );
192  msg.Send( client );
193  }
194 }
195 
196 void send_invulhealthbar( Client* client, const Character* chr )
197 {
198  if ( client->ClientType & Network::CLIENTTYPE_UOKR )
199  {
201  chr->serial_ext, Network::HealthBarStatusUpdate::Color::YELLOW, chr->invul() );
202  msg.Send( client );
203  }
204 }
205 
206 void send_owncreate( Client* client, const Character* chr )
207 {
209  owncreate->offset += 2;
210  owncreate->Write<u32>( chr->serial_ext );
211  owncreate->WriteFlipped<u16>( chr->graphic );
212  owncreate->WriteFlipped<u16>( chr->x );
213  owncreate->WriteFlipped<u16>( chr->y );
214  owncreate->Write<s8>( chr->z );
215  owncreate->Write<u8>( chr->facing );
216  owncreate->WriteFlipped<u16>( chr->color );
217  owncreate->Write<u8>( chr->get_flag1( client ) );
218  owncreate->Write<u8>( chr->hilite_color_idx( client->chr ) );
219 
220  for ( int layer = LAYER_EQUIP__LOWEST; layer <= LAYER_EQUIP__HIGHEST; ++layer )
221  {
222  const Item* item = chr->wornitem( layer );
223  if ( item == nullptr )
224  continue;
225 
226  // Dont send faces if older client or ssopt
227  if ( ( layer == LAYER_FACE ) && ( ( settingsManager.ssopt.support_faces == 0 ) ||
228  ( ~client->ClientType & CLIENTTYPE_UOKR ) ) )
229  continue;
230 
231  if ( client->ClientType & CLIENTTYPE_70331 )
232  {
233  owncreate->Write<u32>( item->serial_ext );
234  owncreate->WriteFlipped<u16>( item->graphic );
235  owncreate->Write<u8>( static_cast<u8>( layer ) );
236  owncreate->WriteFlipped<u16>( item->color );
237  }
238  else if ( item->color )
239  {
240  owncreate->Write<u32>( item->serial_ext );
241  owncreate->WriteFlipped<u16>( 0x8000u | item->graphic );
242  owncreate->Write<u8>( static_cast<u8>( layer ) );
243  owncreate->WriteFlipped<u16>( item->color );
244  }
245  else
246  {
247  owncreate->Write<u32>( item->serial_ext );
248  owncreate->WriteFlipped<u16>( item->graphic );
249  owncreate->Write<u8>( static_cast<u8>( layer ) );
250  }
251  }
252  owncreate->offset += 4; // items nullterm
253  u16 len = owncreate->offset;
254  owncreate->offset = 1;
255  owncreate->WriteFlipped<u16>( len );
256 
257  owncreate.Send( client, len );
258 
259  if ( client->UOExpansionFlag & AOS )
260  {
261  send_object_cache( client, chr );
262  // 07/11/09 Turley: moved to bottom first the client needs to know the item then we can send
263  // revision
264  for ( int layer = LAYER_EQUIP__LOWEST; layer <= LAYER_EQUIP__HIGHEST; ++layer )
265  {
266  const Item* item = chr->wornitem( layer );
267  if ( item == nullptr )
268  continue;
269  if ( layer == LAYER_FACE )
270  continue;
271  send_object_cache( client, item );
272  }
273  }
274 
275  if ( chr->poisoned() ) // if poisoned send 0x17 for newer clients
276  send_poisonhealthbar( client, chr );
277 
278  if ( chr->invul() ) // if invul send 0x17 for newer clients
279  send_invulhealthbar( client, chr );
280 }
281 
282 void build_owncreate( const Character* chr, PktOut_78* owncreate )
283 {
284  owncreate->offset += 2;
285  owncreate->Write<u32>( chr->serial_ext );
286  owncreate->WriteFlipped<u16>( chr->graphic );
287  owncreate->WriteFlipped<u16>( chr->x );
288  owncreate->WriteFlipped<u16>( chr->y );
289  owncreate->Write<s8>( chr->z );
290  owncreate->Write<u8>( chr->facing );
291  owncreate->WriteFlipped<u16>( chr->color ); // 17
292 }
293 void send_owncreate( Client* client, const Character* chr, PktOut_78* owncreate )
294 {
295  owncreate->offset = 17;
296  owncreate->Write<u8>( chr->get_flag1( client ) );
297  owncreate->Write<u8>( chr->hilite_color_idx( client->chr ) );
298 
299  for ( int layer = LAYER_EQUIP__LOWEST; layer <= LAYER_EQUIP__HIGHEST; ++layer )
300  {
301  const Item* item = chr->wornitem( layer );
302  if ( item == nullptr )
303  continue;
304 
305  // Dont send faces if older client or ssopt
306  if ( ( layer == LAYER_FACE ) && ( ( settingsManager.ssopt.support_faces == 0 ) ||
307  ( ~client->ClientType & CLIENTTYPE_UOKR ) ) )
308  continue;
309 
310  if ( client->ClientType & CLIENTTYPE_70331 )
311  {
312  owncreate->Write<u32>( item->serial_ext );
313  owncreate->WriteFlipped<u16>( item->graphic );
314  owncreate->Write<u8>( static_cast<u16>( layer ) );
315  owncreate->WriteFlipped<u16>( item->color );
316  }
317  else if ( item->color )
318  {
319  owncreate->Write<u32>( item->serial_ext );
320  owncreate->WriteFlipped<u16>( 0x8000u | item->graphic );
321  owncreate->Write<u8>( static_cast<u8>( layer ) );
322  owncreate->WriteFlipped<u16>( item->color );
323  }
324  else
325  {
326  owncreate->Write<u32>( item->serial_ext );
327  owncreate->WriteFlipped<u16>( item->graphic );
328  owncreate->Write<u8>( static_cast<u8>( layer ) );
329  }
330  }
331  owncreate->offset += 4; // items nullterm
332  u16 len = owncreate->offset;
333  owncreate->offset = 1;
334  owncreate->WriteFlipped<u16>( len );
335 
336  Core::networkManager.clientTransmit->AddToQueue( client, &owncreate->buffer, len );
337 
338  if ( client->UOExpansionFlag & AOS )
339  {
340  send_object_cache( client, chr );
341  // 07/11/09 Turley: moved to bottom first the client needs to know the item then we can send
342  // revision
343  for ( int layer = LAYER_EQUIP__LOWEST; layer <= LAYER_EQUIP__HIGHEST; ++layer )
344  {
345  const Item* item = chr->wornitem( layer );
346  if ( item == nullptr )
347  continue;
348  if ( layer == LAYER_FACE )
349  continue;
350  send_object_cache( client, item );
351  }
352  }
353 }
354 
355 void send_remove_character( Client* client, const Character* chr )
356 {
357  if ( !client->ready ) /* if a client is just connecting, don't bother him. */
358  return;
359 
360  /* Don't remove myself */
361  if ( client->chr == chr )
362  return;
363  Network::RemoveObjectPkt msgremove( chr->serial_ext );
364  msgremove.Send( client );
365 }
366 
369 {
370  if ( !client->ready ) /* if a client is just connecting, don't bother him. */
371  return;
372 
373  /* Don't remove myself */
374  if ( client->chr == chr )
375  return;
376  pkt.Send( client );
377 }
378 
380 {
381  Network::RemoveObjectPkt msgremove( chr->serial_ext );
383  if ( zonechr == chr )
384  return;
385  msgremove.Send( zonechr->client );
386  } );
387 }
388 
390 {
391  Network::RemoveObjectPkt msgremove( chr->serial_ext );
393  if ( zonechr == chr )
394  return;
395  if ( !zonechr->is_visible_to_me( chr ) )
396  msgremove.Send( zonechr->client );
397  } );
398 }
399 
401 {
402  Network::RemoveObjectPkt msgremove( chr->serial_ext );
404  if ( _chr != chr && _chr->is_visible_to_me( chr ) )
405  msgremove.Send( _chr->client );
406  } );
407 }
408 
409 void send_remove_object_if_inrange( Client* client, const Item* item )
410 {
411  if ( !client->ready ) /* if a client is just connecting, don't bother him. */
412  return;
413 
414  if ( !inrange( client->chr, item ) )
415  return;
416  Network::RemoveObjectPkt msgremove( item->serial_ext );
417  msgremove.Send( client );
418 }
419 
420 void send_remove_object( Client* client, const UObject* object )
421 {
422  if ( client == nullptr || !client->ready )
423  return;
424  Network::RemoveObjectPkt msgremove( object->serial_ext );
425  msgremove.Send( client );
426 }
427 
428 void send_remove_object_to_inrange( const UObject* centerObject )
429 {
430  Network::RemoveObjectPkt msgremove( centerObject->serial_ext );
432  centerObject, [&]( Character* chr ) { msgremove.Send( chr->client ); } );
433 }
434 
435 void send_remove_object( Client* client, const UObject* item, RemoveObjectPkt& pkt )
436 {
437  if ( !client->ready ) /* if a client is just connecting, don't bother him. */
438  return;
439  pkt.update( item->serial_ext );
440  pkt.Send( client );
441 }
442 
443 bool inrangex( const Character* c1, const Character* c2, int maxdist )
444 {
445  return ( ( c1->realm == c2->realm ) && ( abs( c1->x - c2->x ) <= maxdist ) &&
446  ( abs( c1->y - c2->y ) <= maxdist ) );
447 }
448 
449 bool inrangex( const UObject* c1, unsigned short x, unsigned short y, int maxdist )
450 {
451  return ( ( abs( c1->x - x ) <= maxdist ) && ( abs( c1->y - y ) <= maxdist ) );
452 }
453 
454 bool inrange( const UObject* c1, unsigned short x, unsigned short y )
455 {
456  return ( ( abs( c1->x - x ) <= RANGE_VISUAL ) && ( abs( c1->y - y ) <= RANGE_VISUAL ) );
457 }
458 
459 bool inrange( const Mobile::Character* c1, const Mobile::Character* c2 )
460 {
461  // note, these are unsigned. abs converts to signed, so everything _should_ be okay.
462  return ( ( c1->realm == c2->realm ) && ( abs( c1->x - c2->x ) <= RANGE_VISUAL ) &&
463  ( abs( c1->y - c2->y ) <= RANGE_VISUAL ) );
464 }
465 
466 bool inrange( const Mobile::Character* c1, const UObject* obj )
467 {
468  obj = obj->toplevel_owner();
469 
470  return ( ( c1->realm == obj->realm ) && ( abs( c1->x - obj->x ) <= RANGE_VISUAL ) &&
471  ( abs( c1->y - obj->y ) <= RANGE_VISUAL ) );
472 }
473 
474 bool multi_inrange( const Mobile::Character* c1, const Multi::UMulti* obj )
475 {
476  return ( ( c1->realm == obj->realm ) &&
477  ( abs( c1->x - obj->x ) <= RANGE_VISUAL_LARGE_BUILDINGS ) &&
478  ( abs( c1->y - obj->y ) <= RANGE_VISUAL_LARGE_BUILDINGS ) );
479 }
480 
481 unsigned short pol_distance( unsigned short x1, unsigned short y1, unsigned short x2,
482  unsigned short y2 )
483 {
484  int xd = abs( x1 - x2 );
485  int yd = abs( y1 - y2 );
486  if ( xd > yd )
487  return static_cast<unsigned short>( xd );
488  else
489  return static_cast<unsigned short>( yd );
490 }
491 
492 unsigned short pol_distance( const Mobile::Character* c1, const UObject* obj )
493 {
494  obj = obj->toplevel_owner();
495 
496  int xd = abs( c1->x - obj->x );
497  int yd = abs( c1->y - obj->y );
498  if ( xd > yd )
499  return static_cast<unsigned short>( xd );
500  else
501  return static_cast<unsigned short>( yd );
502 }
503 
504 bool in_say_range( const Character* c1, const Character* c2 )
505 {
506  return inrangex( c1, c2, settingsManager.ssopt.speech_range );
507 }
508 bool in_yell_range( const Character* c1, const Character* c2 )
509 {
510  return inrangex( c1, c2, settingsManager.ssopt.yell_range );
511 }
512 bool in_whisper_range( const Character* c1, const Character* c2 )
513 {
514  return inrangex( c1, c2, settingsManager.ssopt.whisper_range );
515 }
516 
517 bool inrange( unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2 )
518 {
519  return ( ( abs( x1 - x2 ) <= RANGE_VISUAL ) && ( abs( y1 - y2 ) <= RANGE_VISUAL ) );
520 }
521 
522 bool multi_inrange( unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2 )
523 {
524  return ( ( abs( x1 - x2 ) <= RANGE_VISUAL_LARGE_BUILDINGS ) &&
525  ( abs( y1 - y2 ) <= RANGE_VISUAL_LARGE_BUILDINGS ) );
526 }
527 
528 void send_put_in_container( Client* client, const Item* item )
529 {
530  auto msg = Network::AddItemContainerMsg(
531  item->serial_ext, item->graphic, item->get_senditem_amount(), item->x, item->y,
532  item->slot_index(), item->container->serial_ext, item->color );
533  msg.Send( client );
534 
535  if ( client->UOExpansionFlag & AOS )
536  send_object_cache( client, item );
537 }
538 
540 {
541  auto msg = Network::AddItemContainerMsg(
542  item->serial_ext, item->graphic, item->get_senditem_amount(), item->x, item->y,
543  item->slot_index(), item->container->serial_ext, item->color );
544 
545  auto pkt_rev = Network::ObjRevisionPkt( item->serial_ext, item->rev() );
546 
547  // FIXME mightsee also checks remote containers thus the ForEachPlayer functions cannot be used
548  for ( auto& client2 : networkManager.clients )
549  {
550  if ( !client2->ready )
551  continue;
552  // FIXME need to check character's additional_legal_items.
553  // looks like inrange should be a Character member function.
554  if ( client2->chr->mightsee( item->container ) )
555  {
556  // FIXME if the container has an owner, and I'm not it, don't tell me?
557  msg.Send( client2 );
558  pkt_rev.Send( client2 );
559  }
560  }
561 }
562 
563 // An item is visible on a corpse if:
564 // - it's visible
565 // - or the chr has seeinvisitems() privilege
566 // - it's hair or beard
567 bool can_see_on_corpse( const Client* client, const Item* item )
568 {
569  bool invisible =
570  ( item->invisible() && !client->chr->can_seeinvisitems() && item->layer != Core::LAYER_HAIR &&
571  item->layer != Core::LAYER_BEARD && item->layer != Core::LAYER_FACE );
572 
573  return !invisible;
574 }
575 
576 // Helper function for send_corpse_items(). Sends packet 0x89 containing information
577 // of equipped items on the corpse.
578 void send_corpse_equip( Client* client, const UCorpse* corpse )
579 {
581  msg->offset += 2;
582  msg->Write<u32>( corpse->serial_ext );
583 
584  for ( unsigned layer = Core::LOWEST_LAYER; layer <= Core::HIGHEST_LAYER; ++layer )
585  {
586  Item* item2 = corpse->GetItemOnLayer( layer );
587 
588  if ( !item2 )
589  continue;
590 
591  if ( !can_see_on_corpse( client, item2 ) )
592  continue;
593 
594  msg->Write<u8>( item2->layer );
595  msg->Write<u32>( item2->serial_ext );
596  }
597 
598  msg->offset += 1; // nullterm byte
599  u16 len = msg->offset;
600  msg->offset = 1;
601  msg->WriteFlipped<u16>( len );
602 
603  msg.Send( client, len );
604 }
605 
606 // Helper function for send_corpse_items(). No need to send the full corpse contents,
607 // just the equipped items. Uses packet 0x3C.
608 void send_corpse_contents( Client* client, const UCorpse* corpse )
609 {
611  msg->offset += 4; // msglen+count
612  u16 count = 0;
613 
614  for ( unsigned layer = Core::LOWEST_LAYER; layer <= Core::HIGHEST_LAYER; ++layer )
615  {
616  const Items::Item* item = corpse->GetItemOnLayer( layer );
617 
618  if ( !item )
619  continue;
620 
621  if ( !can_see_on_corpse( client, item ) )
622  continue;
623 
624  msg->Write<u32>( item->serial_ext );
625  msg->WriteFlipped<u16>( item->graphic );
626  msg->offset++; // unk6
627  msg->WriteFlipped<u16>( item->get_senditem_amount() );
628  msg->WriteFlipped<u16>( item->x );
629  msg->WriteFlipped<u16>( item->y );
630  if ( client->ClientType & CLIENTTYPE_6017 )
631  msg->Write<u8>( item->slot_index() );
632  msg->Write<u32>( corpse->serial_ext );
633  msg->WriteFlipped<u16>( item->color ); // color
634  ++count;
635  }
636 
637  u16 len = msg->offset;
638  msg->offset = 1;
639  msg->WriteFlipped<u16>( len );
640  msg->WriteFlipped<u16>( count );
641  msg.Send( client, len );
642 }
643 
644 // FIXME it would be better to compose this message once and
645 // send to multiple clients.
646 //
647 // The corpse requires a packet (0x89) to say which items are equipped and another (0x3C)
648 // to describe the equipped items (similar packet as in the send_container_contents(), but
649 // just the outside items).
650 
651 void send_corpse( Client* client, const Item* item )
652 {
653  const UCorpse* corpse = static_cast<const UCorpse*>( item );
654  send_corpse_equip( client, corpse );
655  send_corpse_contents( client, corpse );
656 }
657 
658 // This function sends every item in the corpse, not only the equipped items. It's mainly
659 // used to tell the player that he's now dead and his items are in the corpse.
660 void send_full_corpse( Client* client, const Item* item )
661 {
662  const UCorpse* corpse = static_cast<const UCorpse*>( item );
663  send_corpse_equip( client, corpse );
664  send_container_contents( client, *corpse );
665 }
666 
667 void send_corpse_equip_inrange( const Item* item )
668 {
669  const UCorpse* corpse = static_cast<const UCorpse*>( item );
670 
672  corpse, [&]( Character* chr ) { send_corpse_equip( chr->client, corpse ); } );
673 }
674 
675 // Item::sendto( Client* ) ??
676 void send_item( Client* client, const Item* item )
677 {
678  if ( item->invisible() && !client->chr->can_seeinvisitems() )
679  {
680  send_remove_object( client, item );
681  return;
682  }
683 
684  u8 flags = 0;
685  if ( client->chr->can_move( item ) )
686  flags |= ITEM_FLAG_FORCE_MOVABLE;
687 
688  auto pkt = SendWorldItem( item->serial, item->graphic, item->get_senditem_amount(), item->x,
689  item->y, item->z, item->facing, item->color, flags );
690  pkt.Send( client );
691 
692  // if the item is a corpse, transmit items contained by it
693  if ( item->objtype_ == UOBJ_CORPSE )
694  {
695  send_corpse( client, item );
696  }
697 
698  if ( client->UOExpansionFlag & AOS )
699  {
700  send_object_cache( client, item );
701  return;
702  }
703 }
704 
705 /* Tell all clients new information about an item */
706 void send_item_to_inrange( const Item* item )
707 {
708  auto pkt = SendWorldItem( item->serial, item->graphic, item->get_senditem_amount(), item->x,
709  item->y, item->z, item->facing, item->color, 0 );
710  auto pkt_remove = RemoveObjectPkt( item->serial_ext );
711  auto pkt_rev = ObjRevisionPkt( item->serial_ext, item->rev() );
712 
714  if ( item->invisible() && !zonechr->client->chr->can_seeinvisitems() )
715  {
716  pkt_remove.Send( zonechr->client );
717  return;
718  }
719 
720  u8 flags = 0;
721  if ( zonechr->client->chr->can_move( item ) )
722  flags |= ITEM_FLAG_FORCE_MOVABLE;
723  pkt.updateFlags( flags );
724  pkt.Send( zonechr->client );
725 
726  // if the item is a corpse, transmit items contained by it
727  if ( item->objtype_ == UOBJ_CORPSE )
728  {
729  send_corpse( zonechr->client, item );
730  }
731 
732  pkt_rev.Send( zonechr->client );
733  } );
734 }
735 
736 
737 void update_item_to_inrange( const Item* item )
738 {
739  if ( item->container != nullptr )
740  {
741  if ( IsCharacter( item->container->serial ) )
742  {
743  // this may not be the right thing in all cases.
744  // specifically, handle_dye used to not ever do send_wornitem.
745  // FIXME way, way inefficient, but nontrivial.
746  Character* chr = find_character( item->container->serial );
747  if ( chr )
748  {
749  update_wornitem_to_inrange( chr, item );
750  }
751  else
752  POLLOG_ERROR.Format( "Ack! update_item_to_inrange: character 0x{:X} doesn't exist!\n" )
753  << item->container->serial;
754  }
755  else
756  {
758  }
759  }
760  else
761  {
762  send_item_to_inrange( item );
763  }
764 }
765 
766 void send_light( Client* client, int lightlevel )
767 {
768  if ( VALID_LIGHTLEVEL( lightlevel ) )
769  {
771  msg->Write<u8>( static_cast<u8>( lightlevel ) );
772  msg.Send( client );
773  }
774 }
775 
776 void send_weather( Client* client, u8 type, u8 severity, u8 aux )
777 {
779  msg->Write<u8>( type );
780  msg->Write<u8>( severity );
781  msg->Write<u8>( aux );
782  msg.Send( client );
783 }
784 
785 /* send_char_data: called once for each client when a new character enters
786  the world. */
787 void send_char_data( Client* client, Character* chr )
788 {
789  if ( !client->ready )
790  return;
791 
792  if ( !client->chr->is_visible_to_me( chr ) )
793  return;
794 
795  if ( inrange( client->chr, chr ) )
796  {
797  send_owncreate( client, chr );
798  }
799 }
800 
801 /* send_client_char_data: called once for each character when a client
802  logs on. If in range, tell the client about each character. */
804 {
805  // Don't tell a client about its own character.
806  if ( client->chr == chr )
807  return;
808 
809  if ( !client->chr->is_visible_to_me( chr ) )
810  return;
811 
812  if ( inrange( client->chr, chr ) )
813  {
814  send_owncreate( client, chr );
815  }
816 }
817 
819 {
821  msg->Write<u8>( reason );
822  msg.Send( client );
823 }
824 
825 void send_wornitem( Client* client, const Character* chr, const Item* item )
826 {
828  msg->Write<u32>( item->serial_ext );
829  msg->WriteFlipped<u16>( item->graphic );
830  msg->offset++; // unk7
831  msg->Write<u8>( item->layer );
832  msg->Write<u32>( chr->serial_ext );
833  msg->WriteFlipped<u16>( item->color );
834  msg.Send( client );
835 
836  if ( client->UOExpansionFlag & AOS )
837  {
838  send_object_cache( client, item );
839  }
840 }
841 
842 void send_wornitem_to_inrange( const Character* chr, const Item* item )
843 {
845  msg->Write<u32>( item->serial_ext );
846  msg->WriteFlipped<u16>( item->graphic );
847  msg->offset++; // unk7
848  msg->Write<u8>( item->layer );
849  msg->Write<u32>( chr->serial_ext );
850  msg->WriteFlipped<u16>( item->color );
851  transmit_to_inrange( item, &msg->buffer, msg->offset );
853 }
854 
855 // This used when item already worn and graphic/color changed. Deletes the item
856 // at client and then sends the new information.
857 void update_wornitem_to_inrange( const Character* chr, const Item* item )
858 {
859  if ( chr != nullptr )
860  {
862 
864  msg->Write<u32>( item->serial_ext );
865  msg->WriteFlipped<u16>( item->graphic );
866  msg->offset++; // unk7
867  msg->Write<u8>( item->layer );
868  msg->Write<u32>( chr->serial_ext );
869  msg->WriteFlipped<u16>( item->color );
870  transmit_to_inrange( item, &msg->buffer, msg->offset );
871 
873  }
874 }
875 
876 // does 'item' have a parent with serial 'serial'?
877 bool is_a_parent( const Item* item, u32 serial )
878 {
879  while ( item->container != nullptr )
880  {
881  // UNTESTED
882  item = item->container;
883  if ( item->serial == serial )
884  return true;
885  }
886  return false;
887 }
888 
889 
890 // search for a container that this character can legally act upon
891 // - remove items, insert items, etc.
893 {
894  UContainer* cont;
895  cont = chr->backpack();
896  if ( cont )
897  {
898  if ( serial == cont->serial )
899  return cont;
900  // not the main backpack, look for subpacks.
901  cont = cont->find_container( serial );
902  if ( cont )
903  return cont;
904  }
905 
906  // 4/2007 - MuadDib
907  // Wasn't in backpack, check wornitems
908  cont = nullptr;
909  Item* worn_item = chr->find_wornitem( serial );
910  if ( worn_item != nullptr && worn_item->script_isa( POLCLASS_CONTAINER ) )
911  {
912  // Ignore these layers explicitly. Backpack especially since it was
913  // already checked above.
914  if ( worn_item->layer != LAYER_HAIR && worn_item->layer != LAYER_FACE &&
915  worn_item->layer != LAYER_BEARD && worn_item->layer != LAYER_BACKPACK &&
916  worn_item->layer != LAYER_MOUNT )
917  {
918  UContainer* worn_cont = static_cast<UContainer*>( worn_item );
919  if ( worn_cont != nullptr )
920  return worn_cont;
921  }
922  }
923 
924 
925  // not in the backpack, or in a subpack. check global items and subpacks.
926  // FIXME doesn't check range?
927  unsigned short wxL, wyL, wxH, wyH;
928  zone_convert_clip( chr->x - 8, chr->y - 8, chr->realm, &wxL, &wyL );
929  zone_convert_clip( chr->x + 8, chr->y + 8, chr->realm, &wxH, &wyH );
930  for ( unsigned short wx = wxL; wx <= wxH; ++wx )
931  {
932  for ( unsigned short wy = wyL; wy <= wyH; ++wy )
933  {
934  for ( auto& item : chr->realm->zone[wx][wy].items )
935  {
936  if ( item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
937  {
938  cont = (UContainer*)item;
939  if ( serial == cont->serial )
940  return cont;
941  cont = cont->find_container( serial );
942  if ( cont )
943  return cont;
944  }
945  }
946  }
947  }
948 
949  Item* item =
950  chr->search_remote_containers( serial, nullptr /* don't care if it's a remote container */ );
951  if ( item != nullptr && item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
952  return static_cast<UContainer*>( item );
953  else
954  return nullptr;
955 }
956 
957 // assume if you pass additlegal or isRemoteContainer, you init to false
958 Item* find_legal_item( const Character* chr, u32 serial, bool* additlegal, bool* isRemoteContainer )
959 {
960  UContainer* backpack = chr->backpack();
961  if ( backpack != nullptr && backpack->serial == serial )
962  return backpack;
963 
964  // check worn items
965  // 04/2007 - MuadDib Added:
966  // find_wornitem will now check inside containers listed in layers
967  // for normal items now also. This will allow for quivers
968  // in wornitems, handbags, pockets, whatever people want,
969  // to find stuff as a legal item to the character. Treats it
970  // just like the backpack, without making it specific like
971  // a bankbox or backpack.
972  Item* item = chr->find_wornitem( serial );
973  if ( item != nullptr )
974  return item;
975 
976  if ( backpack != nullptr )
977  {
978  item = backpack->find( serial );
979  if ( item != nullptr )
980  return item;
981  }
982 
983  // check items on the ground
984  unsigned short wxL, wyL, wxH, wyH;
985  zone_convert_clip( chr->x - 8, chr->y - 8, chr->realm, &wxL, &wyL );
986  zone_convert_clip( chr->x + 8, chr->y + 8, chr->realm, &wxH, &wyH );
987  for ( unsigned short wx = wxL; wx <= wxH; ++wx )
988  {
989  for ( unsigned short wy = wyL; wy <= wyH; ++wy )
990  {
991  for ( const auto& _item : chr->realm->zone[wx][wy].items )
992  {
993  if ( !inrange( chr, _item ) )
994  continue;
995  if ( _item->serial == serial )
996  {
997  passert_always( _item->container == nullptr );
998  return _item;
999  }
1000  if ( _item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
1001  {
1002  item = ( (const UContainer*)_item )->find( serial );
1003  if ( item != nullptr )
1004  return item;
1005  }
1006  }
1007  }
1008  }
1009 
1010  if ( additlegal != nullptr )
1011  *additlegal = true;
1012  return chr->search_remote_containers( serial, isRemoteContainer );
1013 }
1014 
1015 void play_sound_effect( const UObject* center, u16 effect )
1016 {
1017  Network::PlaySoundPkt msg( PKTOUT_54_FLAG_SINGLEPLAY, effect - 1u, center->x, center->y, 0 );
1018  // FIXME hearing range check perhaps?
1020  center, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1021 }
1022 
1023 void play_sound_effect_xyz( u16 cx, u16 cy, s8 cz, u16 effect, Realms::Realm* realm )
1024 {
1025  Network::PlaySoundPkt msg( PKTOUT_54_FLAG_SINGLEPLAY, effect - 1u, cx, cy, cz );
1027  cx, cy, realm, RANGE_VISUAL, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1028 }
1029 
1030 void play_sound_effect_private( const UObject* center, u16 effect, Character* forchr )
1031 {
1032  if ( forchr->client )
1033  {
1034  Network::PlaySoundPkt msg( PKTOUT_54_FLAG_SINGLEPLAY, effect - 1u, center->x, center->y, 0 );
1035  msg.Send( forchr->client );
1036  }
1037 }
1038 
1039 void play_moving_effect( const UObject* src, const UObject* dst, u16 effect, u8 speed, u8 loop,
1040  u8 explode )
1041 {
1043  msg.movingEffect( src, dst, effect, speed, loop, explode );
1044 
1046  src->toplevel_owner(), [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1048  dst->toplevel_owner(), [&]( Character* zonechr ) {
1049  if ( !inrange( zonechr, src ) ) // send to char only in range of dst
1050  msg.Send( zonechr->client );
1051  } );
1052 }
1053 
1054 void play_moving_effect2( u16 xs, u16 ys, s8 zs, u16 xd, u16 yd, s8 zd, u16 effect, u8 speed,
1055  u8 loop, u8 explode, Realms::Realm* realm )
1056 {
1058  msg.movingEffect( xs, ys, zs, xd, yd, zd, effect, speed, loop, explode );
1059 
1061  xs, ys, realm, RANGE_VISUAL, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1063  xd, yd, realm, RANGE_VISUAL, [&]( Character* zonechr ) {
1064  if ( !inrange( zonechr, xs, ys ) ) // send to chrs only in range of dest
1065  msg.Send( zonechr->client );
1066  } );
1067 }
1068 
1069 
1071 {
1073  msg.lightningBold( center );
1075  center->toplevel_owner(), [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1076 }
1077 
1078 void play_object_centered_effect( const UObject* center, u16 effect, u8 speed, u8 loop )
1079 {
1081  msg.followEffect( center, effect, speed, loop );
1083  center->toplevel_owner(), [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1084 }
1085 
1086 void play_stationary_effect( u16 x, u16 y, s8 z, u16 effect, u8 speed, u8 loop, u8 explode,
1087  Realms::Realm* realm )
1088 {
1090  msg.stationaryEffect( x, y, z, effect, speed, loop, explode );
1092  x, y, realm, RANGE_VISUAL, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1093 }
1094 
1095 void play_stationary_effect_ex( u16 x, u16 y, s8 z, Realms::Realm* realm, u16 effect, u8 speed,
1096  u8 duration, u32 hue, u32 render, u16 effect3d )
1097 {
1099  msg.stationaryEffect( x, y, z, effect, speed, duration, hue, render, effect3d );
1101  x, y, realm, RANGE_VISUAL, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1102 }
1103 
1104 void play_object_centered_effect_ex( const UObject* center, u16 effect, u8 speed, u8 duration,
1105  u32 hue, u32 render, u8 layer, u16 effect3d )
1106 {
1108  msg.followEffect( center, effect, speed, duration, hue, render, layer, effect3d );
1110  center, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1111 }
1112 
1113 void play_moving_effect_ex( const UObject* src, const UObject* dst, u16 effect, u8 speed,
1114  u8 duration, u32 hue, u32 render, u8 direction, u8 explode,
1115  u16 effect3d, u16 effect3dexplode, u16 effect3dsound )
1116 {
1118  msg.movingEffect( src, dst, effect, speed, duration, hue, render, direction, explode, effect3d,
1119  effect3dexplode, effect3dsound );
1120 
1122  src, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1124  if ( !inrange( zonechr, src ) ) // send to chrs only in range of dst
1125  msg.Send( zonechr->client );
1126  } );
1127 }
1128 
1129 void play_moving_effect2_ex( u16 xs, u16 ys, s8 zs, u16 xd, u16 yd, s8 zd, Realms::Realm* realm,
1130  u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 direction,
1131  u8 explode, u16 effect3d, u16 effect3dexplode, u16 effect3dsound )
1132 {
1134  msg.movingEffect( xs, ys, zs, xd, yd, zd, effect, speed, duration, hue, render, direction,
1135  explode, effect3d, effect3dexplode, effect3dsound );
1136 
1138  xs, ys, realm, RANGE_VISUAL, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1140  xd, yd, realm, RANGE_VISUAL, [&]( Character* zonechr ) {
1141  if ( !inrange( zonechr, xs, ys ) ) // send to chrs only in range of dst
1142  msg.Send( zonechr->client );
1143  } );
1144 }
1145 
1146 // System message -- message in lower left corner
1147 void send_sysmessage( Network::Client* client, const char* text, unsigned short font,
1148  unsigned short color )
1149 {
1151  u16 textlen = static_cast<u16>( strlen( text ) + 1 );
1152  if ( textlen > SPEECH_MAX_LEN + 1 ) // FIXME need to handle this better second msg?
1153  textlen = SPEECH_MAX_LEN + 1;
1154 
1155  msg->offset += 2;
1156  msg->Write<u32>( 0x01010101u );
1157  msg->Write<u16>( 0x0101u );
1158  msg->Write<u8>( TEXTTYPE_NORMAL );
1159  msg->WriteFlipped<u16>( color );
1160  msg->WriteFlipped<u16>( font );
1161  msg->Write( "System", 30 );
1162  msg->Write( text, textlen );
1163  u16 len = msg->offset;
1164  msg->offset = 1;
1165  msg->WriteFlipped<u16>( len );
1166  msg.Send( client, len );
1167 }
1168 
1169 // Unicode System message -- message in lower left corner
1170 void send_sysmessage( Network::Client* client, const u16* wtext, const char lang[4],
1171  unsigned short font, unsigned short color )
1172 {
1173  unsigned textlen = 0;
1174  // textlen = wcslen((const wchar_t*)wtext) + 1;
1175  while ( wtext[textlen] != L'\0' )
1176  ++textlen;
1177  if ( textlen > ( SPEECH_MAX_LEN ) ) // FIXME need to handle this better second msg?
1178  textlen = ( SPEECH_MAX_LEN );
1179 
1181  msg->offset += 2;
1182  msg->Write<u32>( 0x01010101u );
1183  msg->Write<u16>( 0x0101u );
1184  msg->Write<u8>( TEXTTYPE_NORMAL );
1185  msg->WriteFlipped<u16>( color );
1186  msg->WriteFlipped<u16>( font );
1187  msg->Write( lang, 4 );
1188  msg->Write( "System", 30 );
1189  msg->WriteFlipped( &wtext[0], static_cast<u16>( textlen ) );
1190  u16 len = msg->offset;
1191  msg->offset = 1;
1192  msg->WriteFlipped<u16>( len );
1193  msg.Send( client, len );
1194 }
1195 
1196 void send_sysmessage( Network::Client* client, const std::string& text, unsigned short font,
1197  unsigned short color )
1198 {
1199  send_sysmessage( client, text.c_str(), font, color );
1200 }
1201 
1202 void send_sysmessage( Network::Client* client, const std::wstring& wtext, const char lang[4],
1203  unsigned short font, unsigned short color )
1204 {
1205  using std::wstring;
1206  u16 uctext[SPEECH_MAX_LEN + 1];
1207  for ( size_t i = 0; i < wtext.length(); i++ )
1208  uctext[i] = static_cast<u16>( wtext[i] );
1209  uctext[wtext.length()] = 0x00;
1210  send_sysmessage( client, uctext, lang, font, color );
1211 }
1212 
1213 void broadcast( const char* text, unsigned short font, unsigned short color,
1214  unsigned short requiredCmdLevel )
1215 {
1216  for ( auto& client : networkManager.clients )
1217  {
1218  if ( !client->ready || client->chr->cmdlevel_ < requiredCmdLevel )
1219  continue;
1220 
1221  send_sysmessage( client, text, font, color );
1222  }
1223 }
1224 
1225 void broadcast( const u16* wtext, const char lang[4], unsigned short font, unsigned short color,
1226  unsigned short requiredCmdLevel )
1227 {
1228  for ( auto& client : networkManager.clients )
1229  {
1230  if ( !client->ready || client->chr->cmdlevel_ < requiredCmdLevel )
1231  continue;
1232 
1233  send_sysmessage( client, wtext, lang, font, color );
1234  }
1235 }
1236 
1237 void send_nametext( Client* client, const Character* chr, const std::string& str )
1238 {
1240  u16 textlen = static_cast<u16>( str.length() + 1 );
1241  if ( textlen > SPEECH_MAX_LEN + 1 )
1242  textlen = SPEECH_MAX_LEN + 1;
1243 
1244  msg->offset += 2;
1245  msg->Write<u32>( chr->serial_ext );
1246  msg->Write<u16>( 0x0101u );
1247  msg->Write<u8>( TEXTTYPE_YOU_SEE );
1248  msg->WriteFlipped<u16>( chr->name_color( client->chr ) ); // 0x03B2
1249  msg->WriteFlipped<u16>( 3u );
1250  msg->Write( str.c_str(), 30 );
1251  msg->Write( str.c_str(), textlen );
1252  u16 len = msg->offset;
1253  msg->offset = 1;
1254  msg->WriteFlipped<u16>( len );
1255  msg.Send( client, len );
1256 }
1257 
1258 bool say_above( const UObject* obj, const char* text, unsigned short font, unsigned short color,
1259  unsigned int journal_print )
1260 {
1262  u16 textlen = static_cast<u16>( strlen( text ) + 1 );
1263  if ( textlen > SPEECH_MAX_LEN + 1 ) // FIXME need to handle this better second msg?
1264  textlen = SPEECH_MAX_LEN + 1;
1265 
1266  msg->offset += 2;
1267  msg->Write<u32>( obj->serial_ext );
1268  msg->WriteFlipped<u16>( obj->graphic );
1269  msg->Write<u8>( TEXTTYPE_NORMAL );
1270  msg->WriteFlipped<u16>( color );
1271  msg->WriteFlipped<u16>( font );
1272  switch ( journal_print )
1273  {
1274  case JOURNAL_PRINT_YOU_SEE:
1275  msg->Write( "You see", 30 );
1276  break;
1277  case JOURNAL_PRINT_NAME:
1278  default:
1279  msg->Write( obj->description().c_str(), 30 );
1280  break;
1281  }
1282  msg->Write( text, textlen );
1283  u16 len = msg->offset;
1284  msg->offset = 1;
1285  msg->WriteFlipped<u16>( len );
1286  // todo: only send to those that I'm visible to.
1287  transmit_to_inrange( obj, &msg->buffer, len );
1288  return true;
1289 }
1290 
1291 bool say_above( const UObject* obj, const u16* wtext, const char lang[4], unsigned short font,
1292  unsigned short color, unsigned int journal_print )
1293 {
1294  unsigned textlen = 0;
1295  // textlen = wcslen((const wchar_t*)wtext) + 1;
1296  while ( wtext[textlen] != L'\0' )
1297  ++textlen;
1298  if ( textlen > ( SPEECH_MAX_LEN ) ) // FIXME need to handle this better second msg?
1299  textlen = ( SPEECH_MAX_LEN );
1300 
1302  msg->offset += 2;
1303  msg->Write<u32>( obj->serial_ext );
1304  msg->WriteFlipped<u16>( obj->graphic );
1305  msg->Write<u8>( TEXTTYPE_NORMAL );
1306  msg->WriteFlipped<u16>( color );
1307  msg->WriteFlipped<u16>( font );
1308  msg->Write( lang, 4 );
1309  switch ( journal_print )
1310  {
1311  case JOURNAL_PRINT_YOU_SEE:
1312  msg->Write( "You see", 30 );
1313  break;
1314  case JOURNAL_PRINT_NAME:
1315  default:
1316  msg->Write( obj->description().c_str(), 30 );
1317  break;
1318  }
1319  msg->WriteFlipped( &wtext[0], static_cast<u16>( textlen ) );
1320  u16 len = msg->offset;
1321  msg->offset = 1;
1322  msg->WriteFlipped<u16>( len );
1323  // todo: only send to those that I'm visible to.
1324  transmit_to_inrange( obj, &msg->buffer, len );
1325  return true;
1326 }
1327 
1328 bool private_say_above( Character* chr, const UObject* obj, const char* text, unsigned short font,
1329  unsigned short color, unsigned int journal_print )
1330 {
1331  if ( chr->client == nullptr )
1332  return false;
1334  u16 textlen = static_cast<u16>( strlen( text ) + 1 );
1335  if ( textlen > SPEECH_MAX_LEN + 1 ) // FIXME need to handle this better second msg?
1336  textlen = SPEECH_MAX_LEN + 1;
1337 
1338  msg->offset += 2;
1339  msg->Write<u32>( obj->serial_ext );
1340  msg->WriteFlipped<u16>( obj->graphic );
1341  msg->Write<u8>( TEXTTYPE_NORMAL );
1342  msg->WriteFlipped<u16>( color );
1343  msg->WriteFlipped<u16>( font );
1344  switch ( journal_print )
1345  {
1346  case JOURNAL_PRINT_YOU_SEE:
1347  msg->Write( "You see", 30 );
1348  break;
1349  case JOURNAL_PRINT_NAME:
1350  default:
1351  msg->Write( obj->description().c_str(), 30 );
1352  break;
1353  }
1354  msg->Write( text, textlen );
1355  u16 len = msg->offset;
1356  msg->offset = 1;
1357  msg->WriteFlipped<u16>( len );
1358  msg.Send( chr->client, len );
1359  return true;
1360 }
1361 
1362 bool private_say_above( Character* chr, const UObject* obj, const u16* wtext, const char lang[4],
1363  unsigned short font, unsigned short color, unsigned int journal_print )
1364 {
1365  unsigned textlen = 0;
1366  // textlen = wcslen((const wchar_t*)wtext) + 1;
1367  while ( wtext[textlen] != L'\0' )
1368  ++textlen;
1369  if ( textlen > ( SPEECH_MAX_LEN ) ) // FIXME need to handle this better second msg?
1370  textlen = ( SPEECH_MAX_LEN );
1371  if ( chr->client == nullptr )
1372  return false;
1373 
1375  msg->offset += 2;
1376  msg->Write<u32>( obj->serial_ext );
1377  msg->WriteFlipped<u16>( obj->graphic );
1378  msg->Write<u8>( TEXTTYPE_NORMAL );
1379  msg->WriteFlipped<u16>( color );
1380  msg->WriteFlipped<u16>( font );
1381  msg->Write( lang, 4 );
1382  switch ( journal_print )
1383  {
1384  case JOURNAL_PRINT_YOU_SEE:
1385  msg->Write( "You see", 30 );
1386  break;
1387  case JOURNAL_PRINT_NAME:
1388  default:
1389  msg->Write( obj->description().c_str(), 30 );
1390  break;
1391  }
1392  msg->WriteFlipped( &wtext[0], static_cast<u16>( textlen ) );
1393  u16 len = msg->offset;
1394  msg->offset = 1;
1395  msg->WriteFlipped<u16>( len );
1396  msg.Send( chr->client, len );
1397  return true;
1398 }
1399 
1400 bool private_say_above_ex( Character* chr, const UObject* obj, const char* text,
1401  unsigned short color )
1402 {
1403  if ( chr->client == nullptr )
1404  return false;
1406  u16 textlen = static_cast<u16>( strlen( text ) + 1 );
1407  if ( textlen > SPEECH_MAX_LEN + 1 ) // FIXME need to handle this better second msg?
1408  textlen = SPEECH_MAX_LEN + 1;
1409 
1410  msg->offset += 2;
1411  msg->Write<u32>( obj->serial_ext );
1412  msg->WriteFlipped<u16>( obj->graphic );
1413  msg->Write<u8>( TEXTTYPE_NORMAL );
1414  msg->WriteFlipped<u16>( color );
1415  msg->WriteFlipped<u16>( 3u );
1416  msg->Write( obj->description().c_str(), 30 );
1417  msg->Write( text, textlen );
1418  u16 len = msg->offset;
1419  msg->offset = 1;
1420  msg->WriteFlipped<u16>( len );
1421  msg.Send( chr->client, len );
1422  return true;
1423 }
1424 
1425 void send_objdesc( Client* client, Item* item )
1426 {
1428  u16 textlen = static_cast<u16>( item->description().length() + 1 );
1429  if ( textlen > SPEECH_MAX_LEN + 1 ) // FIXME need to handle this better second msg?
1430  textlen = SPEECH_MAX_LEN + 1;
1431  msg->offset += 2;
1432  msg->Write<u32>( item->serial_ext );
1433  msg->WriteFlipped<u16>( item->graphic );
1434  msg->Write<u8>( TEXTTYPE_YOU_SEE );
1435  msg->WriteFlipped<u16>( 0x03B2u );
1436  msg->WriteFlipped<u16>( 3u );
1437  msg->Write( "System", 30 );
1438  msg->Write( item->description().c_str(), textlen );
1439  u16 len = msg->offset;
1440  msg->offset = 1;
1441  msg->WriteFlipped<u16>( len );
1442  msg.Send( client, len );
1443 }
1444 
1446 {
1447  Character* chr = client->chr;
1448 
1450  msg->Write<u32>( chr->serial_ext );
1451 
1453  {
1455  if ( v > 0xFFFF )
1456  v = 0xFFFF;
1457  msg->WriteFlipped<u16>( static_cast<u16>( v ) );
1458 
1460  if ( v > 0xFFFF )
1461  v = 0xFFFF;
1462  msg->WriteFlipped<u16>( static_cast<u16>( v ) );
1463  }
1464  else
1465  {
1466  msg->offset += 4;
1467  }
1468  msg.Send( client );
1469 }
1470 
1471 void send_mana_level( Client* client )
1472 {
1473  Character* chr = client->chr;
1474 
1476  msg->Write<u32>( chr->serial_ext );
1477 
1479  {
1481  if ( v > 0xFFFF )
1482  v = 0xFFFF;
1483  msg->WriteFlipped<u16>( static_cast<u16>( v ) );
1484 
1486  if ( v > 0xFFFF )
1487  v = 0xFFFF;
1488  msg->WriteFlipped<u16>( static_cast<u16>( v ) );
1489  }
1490  else
1491  {
1492  msg->offset += 4;
1493  }
1494  msg.Send( client );
1495 }
1496 
1497 void send_death_message( Character* chr_died, Item* corpse )
1498 {
1500  msg->Write<u32>( chr_died->serial_ext );
1501  msg->Write<u32>( corpse->serial_ext );
1502  msg->offset += 4; // u32 unk4_zero
1503 
1505  if ( zonechr == chr_died )
1506  return;
1507  msg.Send( zonechr->client );
1508  } );
1509 }
1510 
1511 void transmit_to_inrange( const UObject* center, const void* msg, unsigned msglen )
1512 {
1514  Core::networkManager.clientTransmit->AddToQueue( zonechr->client, msg, msglen );
1515  } );
1516 }
1517 
1518 void transmit_to_others_inrange( Character* center, const void* msg, unsigned msglen )
1519 {
1521  Client* client = zonechr->client;
1522  if ( zonechr == center )
1523  return;
1524  Core::networkManager.clientTransmit->AddToQueue( client, msg, msglen );
1525  } );
1526 }
1527 
1528 // DAVE made heavy changes to this 11/17 for speed.
1530 {
1531  Character* owner = wornitems->get_chr_owner();
1532  if ( owner != nullptr )
1533  return owner;
1534  else
1535  return nullptr; // fixed 3/8/3
1536 }
1537 
1538 void destroy_item( Item* item )
1539 {
1540  if ( item->serial == 0 )
1541  {
1542  POLLOG_ERROR.Format( "destroy {}: {}, orphan! (old serial: 0x{:X})\n" )
1543  << item->description() << item->classname() << ( cfBEu32( item->serial_ext ) );
1544  }
1545 
1546  if ( item->serial != 0 )
1547  {
1548  /*
1549  cout << "destroy " << item->description() << ": "
1550  << item->classname() << " " << item
1551  << ", serial=" << hexint(item->serial) << endl;
1552  */
1553  item->set_dirty();
1554 
1556 
1557  if ( item->container == nullptr ) // on ground, easy.
1558  {
1559  if ( !item->has_gotten_by() ) // and not in hand
1560  remove_item_from_world( item );
1561  }
1562  else
1563  {
1564  item->extricate();
1565  }
1566 
1567  item->destroy();
1568  }
1569 }
1570 
1571 void setrealm( Item* item, void* arg )
1572 {
1573  Realms::Realm* realm = static_cast<Realms::Realm*>( arg );
1574  item->realm = realm;
1575 }
1576 
1577 void setrealmif( Item* item, void* arg )
1578 {
1579  Realms::Realm* realm = static_cast<Realms::Realm*>( arg );
1580  if ( item->realm == realm )
1581  item->realm = realm->baserealm;
1582 }
1583 
1584 void subtract_amount_from_item( Item* item, unsigned short amount )
1585 {
1586  if ( amount >= item->getamount() )
1587  {
1588  destroy_item( item );
1589  return; // destroy_item will update character weight if item is carried.
1590  }
1591  else
1592  {
1593  item->subamount( amount );
1594  update_item_to_inrange( item );
1595  }
1596  // DAVE added this 11/17: if in a Character's pack, update weight.
1597  UpdateCharacterWeight( item );
1598 }
1599 
1600 
1601 void move_item( Item* item, UFACING facing )
1602 {
1603  u16 oldx = item->x;
1604  u16 oldy = item->y;
1605 
1606  item->x += move_delta[facing].xmove;
1607  item->y += move_delta[facing].ymove;
1608 
1609  item->restart_decay_timer();
1610  MoveItemWorldPosition( oldx, oldy, item, nullptr );
1611 
1613  item, [&]( Character* zonechr ) { send_item( zonechr->client, item ); } );
1614  Network::RemoveObjectPkt msgremove( item->serial_ext );
1616  oldx, oldy, item->realm, RANGE_VISUAL, [&]( Character* zonechr ) {
1617  if ( !inrange( zonechr, item ) ) // not in range. If old loc was in range, send a delete.
1618  msgremove.Send( zonechr->client );
1619  } );
1620 }
1621 
1622 // FIXME: this is called from some places where the item didn't used
1623 // to be on the ground - in a container, say.
1624 // FIXME OPTIMIZE: Core is building the packet in send_item for every single client
1625 // that needs to get it. There should be a better method for this. Such as, a function
1626 // to run all the checks after building the packet here, then send as it needs to.
1627 void move_item( Item* item, unsigned short newx, unsigned short newy, signed char newz,
1628  Realms::Realm* oldrealm )
1629 {
1630  item->set_dirty();
1631 
1632  u16 oldx = item->x;
1633  u16 oldy = item->y;
1634 
1635  item->x = newx;
1636  item->y = newy;
1637  item->z = newz;
1638 
1639  item->restart_decay_timer();
1640  MoveItemWorldPosition( oldx, oldy, item, oldrealm );
1641 
1643  item, [&]( Character* zonechr ) { send_item( zonechr->client, item ); } );
1644  Network::RemoveObjectPkt msgremove( item->serial_ext );
1646  oldx, oldy, oldrealm, RANGE_VISUAL, [&]( Character* zonechr ) {
1647  if ( !inrange( zonechr, item ) ) // not in range. If old loc was in range, send a delete.
1648  msgremove.Send( zonechr->client );
1649  } );
1650 }
1651 
1652 void send_multi( Client* client, const Multi::UMulti* multi )
1653 {
1654  auto pkt = SendWorldMulti( multi->serial_ext, multi->multidef().multiid, multi->x, multi->y,
1655  multi->z, multi->color );
1656  pkt.Send( client );
1657 }
1658 
1660 {
1661  auto pkt = SendWorldMulti( multi->serial_ext, multi->multidef().multiid, multi->x, multi->y,
1662  multi->z, multi->color );
1664  multi, [&]( Character* zonechr ) { pkt.Send( zonechr->client ); } );
1665 }
1666 
1667 
1668 void update_lightregion( Client* client, LightRegion* /*lightregion*/ )
1669 {
1670  if ( !client->ready )
1671  return;
1672 
1673  client->chr->check_light_region_change();
1674 }
1675 
1676 void SetRegionLightLevel( LightRegion* lightregion, int lightlevel )
1677 {
1678  lightregion->lightlevel = lightlevel;
1680  msg->Write<u8>( static_cast<u8>( lightlevel ) );
1681  for ( Clients::iterator itr = networkManager.clients.begin(), end = networkManager.clients.end();
1682  itr != end; ++itr )
1683  {
1684  Client* client = *itr;
1685  if ( !client->ready )
1686  continue;
1687 
1688  auto light_until = client->chr->lightoverride_until();
1689  if ( light_until < read_gameclock() && light_until != ~0u )
1690  {
1691  client->chr->lightoverride_until( 0 );
1692  client->chr->lightoverride( -1 );
1693  }
1694 
1695  if ( client->gd->weather_region && client->gd->weather_region->lightoverride != -1 &&
1696  !client->chr->has_lightoverride() )
1697  continue;
1698 
1699  int newlightlevel;
1700  if ( client->chr->has_lightoverride() )
1701  newlightlevel = client->chr->lightoverride();
1702  else
1703  {
1704  // dave 12-22 check for no regions
1705  LightRegion* light_region =
1706  gamestate.lightdef->getregion( client->chr->x, client->chr->y, client->chr->realm );
1707  if ( light_region != nullptr )
1708  newlightlevel = light_region->lightlevel;
1709  else
1710  newlightlevel = settingsManager.ssopt.default_light_level;
1711  }
1712 
1713  if ( newlightlevel != client->gd->lightlevel )
1714  {
1715  if ( VALID_LIGHTLEVEL( newlightlevel ) )
1716  {
1717  if ( newlightlevel != lightlevel )
1718  {
1719  msg->offset = 1;
1720  msg->Write<u8>( static_cast<u8>( newlightlevel ) );
1721  msg.Send( client );
1722  msg->offset = 1;
1723  msg->Write<u8>( static_cast<u16>( lightlevel ) );
1724  }
1725  else
1726  msg.Send( client );
1727  }
1728  client->gd->lightlevel = newlightlevel;
1729  }
1730  }
1731 }
1732 
1733 void update_weatherregion( Client* client, WeatherRegion* weatherregion )
1734 {
1735  if ( !client->ready )
1736  return;
1737 
1738  if ( client->gd->weather_region == weatherregion )
1739  {
1740  // client->gd->weather_region = nullptr; //dave commented this out 5/26/03, causing no
1741  // processing to happen in following function, added force bool instead.
1742  client->chr->check_weather_region_change( true );
1743  client->chr->check_light_region_change();
1744  }
1745 }
1746 
1747 void SetRegionWeatherLevel( WeatherRegion* weatherregion, unsigned type, unsigned severity,
1748  unsigned aux, int lightoverride )
1749 {
1750  weatherregion->weathertype = static_cast<unsigned char>( type );
1751  weatherregion->severity = static_cast<unsigned char>( severity );
1752  weatherregion->aux = static_cast<unsigned char>( aux );
1753  weatherregion->lightoverride = lightoverride;
1754 
1755  for ( auto& client : networkManager.clients )
1756  {
1757  update_weatherregion( client, weatherregion );
1758  }
1759 }
1760 
1762 {
1763  for ( auto& client : networkManager.clients )
1764  {
1765  if ( !client->ready )
1766  return;
1767 
1768  client->chr->check_weather_region_change();
1769  client->chr->check_light_region_change();
1770  }
1771 }
1772 
1773 /* there are four forms of 'name' in objinfo:
1774  name (normal)
1775  name%s (percent followed by plural-part, then null-term)
1776  name%s% (percent followed by plural-part, then percent, then more)
1777  wheat shea%ves/f% ( '%', plural part, '/', single part, '%', rest )
1778  Some examples:
1779  pil%es/e% of hides
1780  banana%s%
1781  feather%s
1782  Known bugs:
1783  1 gold coin displays as "gold coin". There must be a bit somewhere
1784  that I just don't understand yet.
1785  */
1786 std::string format_description( unsigned int polflags, const std::string& descdef,
1787  unsigned short amount, const std::string suffix )
1788 {
1789  std::string desc;
1790 
1791  if ( amount != 1 )
1792  {
1793  char s[15];
1794  sprintf( s, "%hu ", amount );
1795  desc = s;
1796  }
1798  {
1799  if ( polflags & Plib::FLAG::DESC_PREPEND_AN )
1800  {
1801  desc = "an ";
1802  }
1803  else if ( polflags & Plib::FLAG::DESC_PREPEND_A )
1804  {
1805  desc = "a ";
1806  }
1807  }
1808 
1809  // might want to consider strchr'ing here,
1810  // if not found, strcpy/return
1811  // if found, memcpy up to strchr result, then continue as below.
1812  const char* src = descdef.c_str();
1813  int singular = ( amount == 1 );
1814  int plural_handled = 0;
1815  int phase = 0; /* 0= first part, 1=plural part, 2=singular part, 3=rest */
1816  char ch;
1817  while ( '\0' != ( ch = *src ) )
1818  {
1819  if ( phase == 0 )
1820  {
1821  if ( ch == '%' )
1822  {
1823  plural_handled = 1;
1824  phase = 1;
1825  }
1826  else
1827  {
1828  desc += ch;
1829  }
1830  }
1831  else if ( phase == 1 )
1832  {
1833  if ( ch == '%' )
1834  phase = 3;
1835  else if ( ch == '/' )
1836  phase = 2;
1837  else if ( !singular )
1838  desc += ch;
1839  }
1840  else if ( phase == 2 )
1841  {
1842  if ( ch == '%' )
1843  phase = 3;
1844  else if ( singular )
1845  desc += ch;
1846  }
1847  // if phase == 3 that means there are more words to come,
1848  // lets loop through them to support singular/plural stuff in more than just the first word of
1849  // the desc.
1850  else
1851  {
1852  desc += ch;
1853  phase = 0;
1854  }
1855  ++src;
1856  }
1857 
1858  if ( !singular && !plural_handled )
1859  desc += 's';
1860 
1861  if ( !suffix.empty() )
1862  desc += " " + suffix;
1863 
1864  return desc;
1865 }
1866 
1867 void send_midi( Client* client, u16 midi )
1868 {
1870  msg->WriteFlipped<u16>( midi );
1871  msg.Send( client );
1872  // cout << "Setting midi for " << client->chr->name() << " to " << midi << endl;
1873 }
1874 
1876 {
1877  if ( item->container == nullptr )
1878  {
1879  Multi::UMulti* multi = item->realm->find_supporting_multi( item->x, item->y, item->z );
1880  if ( multi )
1881  multi->register_object( item );
1882  }
1883 }
1884 
1885 
1887 {
1888  if ( client->ready && // must be logged into game
1889  inrange( client->chr, chr ) && client->chr != chr && client->chr->is_visible_to_me( chr ) )
1890  {
1891  send_owncreate( client, chr );
1892  }
1893 }
1894 
1896 {
1898  if ( zonechr == chr )
1899  return;
1900  if ( zonechr->is_visible_to_me( chr ) )
1901  send_owncreate( zonechr->client, chr );
1902  } );
1903 }
1904 
1906 {
1907  MoveChrPkt msgmove( chr );
1909  if ( zonechr == chr )
1910  return;
1911  if ( zonechr->is_visible_to_me( chr ) )
1912  msgmove.Send( zonechr->client );
1913  } );
1914 }
1915 
1917 {
1918  Character* chr_owner = item->GetCharacterOwner();
1919  if ( chr_owner != nullptr && chr_owner->client != nullptr )
1920  {
1921  send_full_statmsg( chr_owner->client, chr_owner );
1922  return chr_owner;
1923  }
1924  return nullptr;
1925 }
1926 
1928 {
1929  Character* chr_owner = item->GetCharacterOwner();
1930  if ( chr_owner != nullptr )
1931  {
1932  if ( item->layer && chr_owner->is_equipped( item ) )
1933  {
1934  item->check_unequiptest_scripts();
1935  item->check_unequip_script();
1937  }
1938  }
1939 }
1940 
1941 // Dave added this 12/1/02
1943 {
1944  return ( c->chr != nullptr );
1945 }
1946 
1948 {
1950  msg.Send( c );
1951 }
1952 
1954 {
1955  u32 clientflag = 0;
1956  switch ( client->acct->uo_expansion_flag() )
1957  {
1958  case TOL:
1959  clientflag = 0x7387DF;
1960  client->UOExpansionFlag =
1961  TOL | HSA | SA | KR | ML | SE |
1962  AOS; // TOL needs HSA- SA- KR- ML- SE- and AOS- features (and used checks) too
1963  break;
1964  case HSA:
1965  clientflag = 0x387DF;
1966  client->UOExpansionFlag =
1967  HSA | SA | KR | ML | SE |
1968  AOS; // HSA needs SA- KR- ML- SE- and AOS- features (and used checks) too
1969  break;
1970  case SA:
1971  clientflag = 0x187DF;
1972  client->UOExpansionFlag =
1973  SA | KR | ML | SE | AOS; // SA needs KR- ML- SE- and AOS- features (and used checks) too
1974  break;
1975  case KR:
1976  clientflag = 0x86DB;
1977  client->UOExpansionFlag =
1978  KR | ML | SE | AOS; // KR needs ML- SE- and AOS-features (and used checks) too
1979  break;
1980  case ML:
1981  clientflag = 0x80DB;
1982  client->UOExpansionFlag = ML | SE | AOS; // ML needs SE- and AOS-features (and used checks) too
1983  break;
1984  case SE:
1985  clientflag = 0x805B;
1986  client->UOExpansionFlag = SE | AOS; // SE needs AOS-features (and used checks) too
1987  break;
1988  case AOS:
1989  clientflag = 0x801B;
1990  client->UOExpansionFlag = AOS;
1991  break;
1992  case LBR:
1993  clientflag = 0x0002;
1994  client->UOExpansionFlag = LBR;
1995  break;
1996  case T2A:
1997  clientflag = 0x0001;
1998  client->UOExpansionFlag = T2A;
1999  break;
2000  default:
2001  break;
2002  }
2003 
2004  // Change flag according to the number of CharacterSlots
2005  if ( client->UOExpansionFlag & AOS )
2006  {
2007  if ( Plib::systemstate.config.character_slots == 7 )
2008  {
2009  clientflag |= 0x1000; // 7th & 6th character flag (B9 Packet)
2010  clientflag &= ~0x0004; // Disable Third Dawn?
2011  }
2012  else if ( Plib::systemstate.config.character_slots == 6 )
2013  {
2014  clientflag |= 0x0020; // 6th character flag (B9 Packet)
2015  clientflag &= ~0x0004;
2016  }
2017  }
2018 
2019  // Roleplay faces?
2020  if ( client->UOExpansionFlag & KR )
2021  {
2022  if ( settingsManager.ssopt.support_faces == 2 )
2023  clientflag |= 0x2000;
2024  }
2025 
2027  if ( client->ClientType & CLIENTTYPE_60142 )
2028  msg->WriteFlipped<u32>( clientflag & 0xFFFFFFFFu );
2029  else
2030  msg->WriteFlipped<u16>( clientflag & 0xFFFFu );
2031  msg.Send( client );
2032 }
2033 
2034 void send_realm_change( Client* client, Realms::Realm* realm )
2035 {
2037  msg->WriteFlipped<u16>( 6u );
2038  msg->offset += 2; // sub
2039  msg->Write<u8>( realm->getUOMapID() );
2040  msg.Send( client );
2041 }
2042 
2044 void send_map_difs( Client* client )
2045 {
2046  // Prepare the data by reading map id used by every realm
2047  // When a map is used multiple times in different realms, only
2048  // take into account first realm found. No support for using the
2049  // same map with different diff files for different realms.
2050  struct mapdiff
2051  {
2052  u32 static_patches;
2053  u32 map_patches;
2054  };
2055  std::map<u32, mapdiff> mapinfo;
2056  for ( auto it = gamestate.Realms.begin(); it != gamestate.Realms.end(); ++it )
2057  {
2058  mapdiff md = {( *it )->getNumStaticPatches(), ( *it )->getNumMapPatches()};
2059  mapinfo.insert( std::pair<u32, mapdiff>( ( *it )->getUOMapID(), md ) );
2060  }
2061 
2062  u32 max_map_id = mapinfo.rbegin()->first;
2063 
2065  msg->offset += 4; // len+sub
2066  msg->WriteFlipped<u32>( max_map_id + 1 ); // Number of maps
2067  for ( u32 i = 0; i <= max_map_id; i++ )
2068  {
2069  auto it = mapinfo.find( i );
2070  if ( it == mapinfo.end() )
2071  {
2072  // Filling hole (map not used)
2073  msg->WriteFlipped<u32>( 0u );
2074  msg->WriteFlipped<u32>( 0u );
2075  }
2076  else
2077  {
2078  msg->WriteFlipped<u32>( mapinfo.at( i ).static_patches );
2079  msg->WriteFlipped<u32>( mapinfo.at( i ).map_patches );
2080  }
2081  }
2082  u16 len = msg->offset;
2083  msg->offset = 1;
2084  msg->WriteFlipped<u16>( len );
2085  msg.Send( client, len );
2086 }
2087 
2088 // FIXME : Works, except for Login. Added length check as to not mess with 1.x clients
2089 // during login. Added send_season_info to handle_client_version to make up.
2090 void send_season_info( Client* client )
2091 {
2092  if ( client->getversiondetail().major >= 1 )
2093  {
2095  msg->Write<u8>( client->chr->realm->season() );
2096  msg->Write<u8>( PKTOUT_BC::PLAYSOUND_YES );
2097  msg.Send( client );
2098 
2099  // Sending Season info resets light level in client, this fixes it during login
2100  if ( client->gd->weather_region != nullptr && client->gd->weather_region->lightoverride != -1 &&
2101  !client->chr->has_lightoverride() )
2102  {
2103  send_light( client, client->gd->weather_region->lightoverride );
2104  }
2105  }
2106 }
2107 
2108 // assumes new realm has been set on client->chr
2110 {
2112  msg->WriteFlipped<u16>( client->chr->x );
2113  msg->WriteFlipped<u16>( client->chr->y );
2114  msg->WriteFlipped<u16>( static_cast<u16>( client->chr->z ) );
2115  msg->offset += 5; // unk0,x1,y2
2116  msg->WriteFlipped<u16>( client->chr->realm->width() );
2117  msg->WriteFlipped<u16>( client->chr->realm->height() );
2118  msg.Send( client );
2119 }
2120 
2121 void send_fight_occuring( Client* client, Character* opponent )
2122 {
2124  msg->offset++; // zero1
2125  msg->Write<u32>( client->chr->serial_ext );
2126  msg->Write<u32>( opponent->serial_ext );
2127  msg.Send( client );
2128 }
2129 
2130 void send_damage( Character* attacker, Character* defender, u16 damage )
2131 {
2132  SendDamagePkt pkt( defender->serial_ext, damage );
2133  if ( attacker->client != nullptr )
2134  pkt.Send( attacker->client );
2135  if ( ( defender->client != nullptr ) && ( attacker != defender ) )
2136  pkt.Send( defender->client );
2137 }
2138 
2139 void sendCharProfile( Character* chr, Character* of_who, const char* title, const u16* utext,
2140  const u16* etext )
2141 {
2143 
2144  size_t newulen = 0, newelen = 0, titlelen;
2145 
2146  while ( utext[newulen] != L'\0' )
2147  ++newulen;
2148 
2149  while ( etext[newelen] != L'\0' )
2150  ++newelen;
2151 
2152  titlelen = strlen( title );
2153 
2154  // Check Lengths
2155 
2156  if ( titlelen > SPEECH_MAX_LEN )
2157  titlelen = SPEECH_MAX_LEN;
2158  if ( newulen > SPEECH_MAX_LEN )
2159  newulen = SPEECH_MAX_LEN;
2160  if ( newelen > SPEECH_MAX_LEN )
2161  newelen = SPEECH_MAX_LEN;
2162 
2163  // Build Packet
2164  msg->offset += 2;
2165  msg->Write<u32>( of_who->serial_ext );
2166  msg->Write( title, static_cast<u16>( titlelen + 1 ) );
2167  msg->WriteFlipped( utext, static_cast<u16>( newulen ) );
2168  msg->WriteFlipped( etext, static_cast<u16>( newelen ) );
2169  u16 len = msg->offset;
2170  msg->offset = 1;
2171  msg->WriteFlipped<u16>( len );
2172  msg.Send( chr->client, len );
2173 }
2174 
2188 void send_buff_message( Character* chr, u16 icon, bool show, u16 duration, u32 cl_name,
2189  u32 cl_descr, std::vector<u32> arguments )
2190 {
2192  msg->offset += 2; // length will be written later
2193  msg->Write<u32>( chr->serial_ext );
2194  msg->WriteFlipped<u16>( icon );
2195  msg->Write<u8>( 0u ); // unknown, always 0
2196  msg->Write<u8>( show ? 1u : 0u );
2197  if ( show )
2198  {
2199  msg->Write<u32>( 0u ); // unknown, always 0
2200  msg->WriteFlipped<u16>( icon );
2201  msg->Write<u8>( 0u ); // unknown, always 0
2202  msg->Write<u8>( 1u ); // unknown, always 1
2203  msg->Write<u32>( 0u ); // unknown, always 0
2204  msg->WriteFlipped<u16>( duration );
2205  msg->Write<u16>( 0u ); // unknown, always 0
2206  msg->Write<u8>( 0u ); // unknown, always 0
2207  msg->WriteFlipped<u32>( cl_name );
2208  msg->WriteFlipped<u32>( cl_descr );
2209  msg->Write<u32>( 0u ); // unknown, always 0
2210  msg->Write<u8>( 0u ); // unknown, always 0
2211  msg->Write<u8>( 1u ); // unknown, always 1
2212  msg->Write<u16>( 20u ); // a space character
2213  msg->Write<u16>( 20u ); // a space character
2214  for ( auto it = arguments.begin(); it != arguments.end(); ++it )
2215  msg->Write<u16>( *it );
2216  msg->Write<u16>( 0u ); // nullptr terminator for unicode string
2217  }
2218 
2219  u16 len = msg->offset;
2220  msg->offset = 1;
2221  msg->WriteFlipped<u16>( len );
2222 
2223  msg.Send( chr->client, len );
2224 }
2225 } // namespace Core
2226 } // namespace Pol
unsigned char u8
Definition: rawtypes.h:25
const u16 HSA
Definition: client.h:82
void play_moving_effect2(u16 xs, u16 ys, s8 zs, u16 xd, u16 yd, s8 zd, u16 effect, u8 speed, u8 loop, u8 explode, Realms::Realm *realm)
Definition: ufunc.cpp:1054
bool poisoned() const
Definition: charactr.h:979
VersionDetailStruct getversiondetail() const
Definition: client.h:164
u16 wyH
Definition: uworld.h:181
std::string format_description(unsigned int polflags, const std::string &descdef, unsigned short amount, const std::string suffix)
Definition: ufunc.cpp:1786
void register_with_supporting_multi(Item *item)
Definition: ufunc.cpp:1875
void check_weather_region_change(bool force=false)
Definition: charactr.cpp:3535
const int JOURNAL_PRINT_NAME
Definition: core.h:89
void movingEffect(const Core::UObject *src, const Core::UObject *dst, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 direction, u8 explode, u16 effect3d, u16 effect3dexplode, u16 effect3dsound)
Definition: packetdefs.cpp:697
virtual std::string description() const POL_OVERRIDE
Definition: item.cpp:150
void broadcast(const char *text, unsigned short font, unsigned short color, unsigned short requiredCmdLevel)
Definition: ufunc.cpp:1213
void login_complete(Client *c)
Definition: ufunc.cpp:1947
UContainer * find_container(u32 serial) const
Definition: containr.cpp:575
void subamount(u16 amount_subtract)
Definition: item.cpp:594
void send_invulhealthbar(Client *client, const Character *chr)
Definition: ufunc.cpp:196
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:401
void send_multi(Network::Client *client, const Multi::UMulti *multi)
Definition: ufunc.cpp:1652
Character * chr_from_wornitems(UContainer *wornitems)
Definition: ufunc.cpp:1529
#define ITEM_FLAG_FORCE_MOVABLE
Definition: pktdef.h:25
void send_remove_character_to_nearby(const Character *chr)
Definition: ufunc.cpp:379
std::enable_if< std::is_same< T, N >::value, void >::type Write(N x)
Definition: packets.h:186
u8 get_flag1(Network::Client *other_client) const
Definition: charactr.cpp:1771
void SetCurrentCharSerialNumber(u32 serial)
Definition: ufunc.cpp:101
unsigned short default_light_level
Definition: ssopt.h:48
void send_full_corpse(Client *client, const Item *item)
Definition: ufunc.cpp:660
unsigned char weathertype
Definition: miscrgn.h:69
void send_nametext(Client *client, const Character *chr, const std::string &str)
Definition: ufunc.cpp:1237
bool check_unequip_script()
Definition: item.cpp:1064
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:442
SystemState systemstate
Definition: systemstate.cpp:12
Network::Client * client
Definition: charactr.h:871
void send_mana_level(Client *client)
Definition: ufunc.cpp:1471
const u16 TOL
Definition: client.h:84
#define RANGE_VISUAL_LARGE_BUILDINGS
Definition: uconst.h:73
const u16 KR
Definition: client.h:78
u16 wyL
Definition: uworld.h:179
bool VALID_LIGHTLEVEL(int lightlevel)
Definition: lightlvl.h:20
virtual Mobile::Character * get_chr_owner()
Definition: containr.h:199
Accounts::Account * acct
Definition: client.h:181
void update_all_weatherregions()
Definition: ufunc.cpp:1761
Items::Item * GetItemOnLayer(unsigned idx) const
Definition: corpse.h:80
bool check_unequiptest_scripts(Mobile::Character *chr)
Definition: item.cpp:1142
u32 GetNextSerialNumber(void)
Definition: ufunc.cpp:119
const u16 ML
Definition: client.h:77
unsigned short whisper_range
Definition: ssopt.h:75
void transmit_to_inrange(const UObject *center, const void *msg, unsigned msglen)
Definition: ufunc.cpp:1511
#define cfBEu32(x)
Definition: clib_endian.h:43
#define SPEECH_MAX_LEN
Definition: pktdef.h:27
unsigned getUOMapID() const
Definition: realm.h:224
unsigned short yell_range
Definition: ssopt.h:76
#define PKTOUT_54_FLAG_SINGLEPLAY
Definition: pktdef.h:119
Items::Item * find(u32 serial) const
Definition: containr.cpp:620
bool is_visible_to_me(const Character *chr) const
Definition: charactr.cpp:2658
void SetRegionWeatherLevel(WeatherRegion *weatherregion, unsigned type, unsigned severity, unsigned aux, int lightoverride)
Definition: ufunc.cpp:1747
bool inrange(const UObject *c1, unsigned short x, unsigned short y)
Definition: ufunc.cpp:454
void lightningBold(const Core::UObject *center)
Definition: packetdefs.cpp:557
bool private_say_above_ex(Mobile::Character *chr, const UObject *obj, const char *text, unsigned short color)
Definition: ufunc.cpp:1400
Character * UpdateCharacterWeight(Item *item)
Definition: ufunc.cpp:1916
void send_new_subserver(Client *client)
Definition: ufunc.cpp:2109
Item * find_legal_item(const Character *chr, u32 serial, bool *additlegal, bool *isRemoteContainer)
Definition: ufunc.cpp:958
Core::WeatherRegion * weather_region
Definition: cgdata.h:75
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:856
void play_moving_effect2_ex(u16 xs, u16 ys, s8 zs, u16 xd, u16 yd, s8 zd, Realms::Realm *realm, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 direction, u8 explode, u16 effect3d, u16 effect3dexplode, u16 effect3dsound)
Definition: ufunc.cpp:1129
void send_light(Client *client, int lightlevel)
Definition: ufunc.cpp:766
void send_multi_to_inrange(const Multi::UMulti *multi)
Definition: ufunc.cpp:1659
void send_create_mobile_if_nearby_cansee(Client *client, const Character *chr)
Definition: ufunc.cpp:1886
virtual void register_object(UObject *obj)
Definition: multis.cpp:60
const u16 SE
Definition: client.h:76
#define POLLOG_ERROR
Definition: logfacility.h:207
int lightlevel(unsigned short x, unsigned short y)
static void InRange(u16 x, u16 y, const Realms::Realm *realm, unsigned range, F &&f)
Definition: uworld.h:235
void send_remove_object_if_inrange(Client *client, const Item *item)
Definition: ufunc.cpp:409
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:163
virtual T * getregion(xcoord x, ycoord y, Realms::Realm *realm)
Definition: region.h:126
virtual unsigned short name_color(const Character *seen_by) const
Definition: repsys.cpp:985
void send_put_in_container_to_inrange(const Item *item)
Definition: ufunc.cpp:539
void followEffect(const Core::UObject *center, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 layer, u16 effect3d)
Definition: packetdefs.cpp:752
LightDef * lightdef
Definition: uvars.h:150
int current_ones() const
Definition: charactr.h:193
MoveDelta move_delta[8]
Definition: ufacing.cpp:16
void play_moving_effect(const UObject *src, const UObject *dst, u16 effect, u8 speed, u8 loop, u8 explode)
Definition: ufunc.cpp:1039
bool can_seeinvisitems() const
Definition: charactr.h:1032
void remove_item_from_world(Items::Item *item)
Definition: uworld.cpp:41
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:384
void send_item_to_inrange(const Item *item)
Definition: ufunc.cpp:706
Mobile::Character * chr
Definition: client.h:182
virtual u16 get_senditem_amount() const
Definition: item.cpp:552
virtual bool script_isa(unsigned isatype) const POL_OVERRIDE
Definition: uoscrobj.cpp:4604
virtual const char * classname() const POL_OVERRIDE
Definition: item.cpp:270
void send_item_move_failure(Network::Client *client, u8 reason)
Definition: ufunc.cpp:818
bool private_say_above(Character *chr, const UObject *obj, const char *text, unsigned short font, unsigned short color, unsigned int journal_print)
Definition: ufunc.cpp:1328
void set_dirty()
Definition: uobject.h:291
unsigned short u16
Definition: rawtypes.h:26
unsigned int u32
Definition: rawtypes.h:27
void zone_convert_clip(int x, int y, const Realms::Realm *realm, unsigned short *wx, unsigned short *wy)
Definition: uworld.h:86
void send_remove_character(Client *client, const Character *chr)
Definition: ufunc.cpp:355
void send_remove_character_to_nearby_cantsee(const Character *chr)
Definition: ufunc.cpp:389
void send_corpse(Client *client, const Item *item)
Definition: ufunc.cpp:651
void stationaryEffect(u16 x, u16 y, s8 z, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u16 effect3d)
Definition: packetdefs.cpp:778
#define RANGE_VISUAL
Definition: uconst.h:72
void play_stationary_effect_ex(u16 x, u16 y, s8 z, Realms::Realm *realm, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u16 effect3d)
Definition: ufunc.cpp:1095
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:835
const u16 AOS
Definition: client.h:75
void send_move_mobile_to_nearby_cansee(const Character *chr)
Definition: ufunc.cpp:1905
void send_poisonhealthbar(Client *client, const Character *chr)
Definition: ufunc.cpp:186
bool in_whisper_range(const Character *c1, const Character *c2)
Definition: ufunc.cpp:512
std::unique_ptr< Network::ClientTransmit > clientTransmit
Definition: network.h:97
void send_move(Client *client, const Character *chr)
Definition: ufunc.cpp:174
Realm * baserealm
Definition: realm.h:66
virtual void destroy()
Definition: uobject.cpp:122
void send_midi(Client *client, u16 midi)
Definition: ufunc.cpp:1867
std::enable_if< std::is_same< T, N >::value, void >::type WriteFlipped(N x)
Definition: packets.h:217
bool in_say_range(const Character *c1, const Character *c2)
Definition: ufunc.cpp:504
void destroy_item(Item *item)
Definition: ufunc.cpp:1538
void send_goxyz(Client *client, const Character *chr)
Definition: ufunc.cpp:149
u16 wxH
Definition: uworld.h:180
unsigned season() const
Definition: realm.cpp:114
void play_object_centered_effect_ex(const UObject *center, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 layer, u16 effect3d)
Definition: ufunc.cpp:1104
std::vector< Realms::Realm * > Realms
Definition: uvars.h:163
unsigned char aux
Definition: miscrgn.h:71
u32 GetNewItemSerialNumber(void)
Definition: ufunc.cpp:142
NetworkManager networkManager
Definition: network.cpp:28
void send_damage(Character *attacker, Character *defender, u16 damage)
Definition: ufunc.cpp:2130
bool is_a_parent(const Item *item, u32 serial)
Definition: ufunc.cpp:877
unsigned short height() const
Definition: realm.h:245
void send_feature_enable(Client *client)
Definition: ufunc.cpp:1953
void send_remove_object(Client *client, const UObject *object)
Definition: ufunc.cpp:420
void Send(Client *client, int len=-1) const
Definition: packethelper.h:69
u32 UseCharSerialNumber(u32 serial)
Definition: ufunc.cpp:126
void update_wornitem_to_inrange(const Character *chr, const Item *item)
Definition: ufunc.cpp:857
void play_sound_effect(const UObject *center, u16 effect)
Definition: ufunc.cpp:1015
#define UOBJ_CORPSE
Definition: objtype.h:218
void play_sound_effect_xyz(u16 cx, u16 cy, s8 cz, u16 effect, Realms::Realm *realm)
Definition: ufunc.cpp:1023
const unsigned POLCLASS_CONTAINER
Definition: polclass.h:18
u32 UseItemSerialNumber(u32 serial)
Definition: ufunc.cpp:134
UContainer * find_legal_container(const Character *chr, u32 serial)
Definition: ufunc.cpp:892
void setrealm(Item *item, void *arg)
Definition: ufunc.cpp:1571
void send_death_message(Character *chr_died, Item *corpse)
Definition: ufunc.cpp:1497
virtual unsigned char hilite_color_idx(const Character *seen_by) const
Definition: repsys.cpp:981
void send_fight_occuring(Client *client, Character *opponent)
Definition: ufunc.cpp:2121
signed char s8
Definition: rawtypes.h:29
void send_corpse_equip_inrange(const Item *item)
Definition: ufunc.cpp:667
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:15
ClientGameData * gd
Definition: client.h:252
virtual UObject * toplevel_owner()
Definition: uobject.cpp:234
Core::UContainer * container
Definition: item.h:256
void stationaryEffect(u16 xs, u16 ys, s8 zs, u16 effect, u8 speed, u8 loop, u8 explode)
Definition: packetdefs.cpp:593
unsigned short speech_range
Definition: ssopt.h:74
gameclock_t read_gameclock()
Reads the current value of the game clock.
Definition: gameclck.cpp:57
int maximum_ones() const
Definition: charactr.h:200
const u32 objtype_
Definition: uobject.h:249
GameState gamestate
Definition: uvars.cpp:74
void send_remove_object_to_inrange(const UObject *centerObject)
Definition: ufunc.cpp:428
const int JOURNAL_PRINT_YOU_SEE
Definition: core.h:90
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:225
void send_full_statmsg(Network::Client *client, Mobile::Character *chr)
Definition: statmsg.cpp:32
const u16 T2A
Definition: client.h:73
Mobile::Character * find_character(u32 serial)
Definition: fnsearch.cpp:60
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:881
void send_realm_change(Client *client, Realms::Realm *realm)
Definition: ufunc.cpp:2034
void move_item(Item *item, UFACING facing)
Definition: ufunc.cpp:1601
void send_stamina_level(Client *client)
Definition: ufunc.cpp:1445
void send_wornitem(Client *client, const Character *chr, const Item *item)
Definition: ufunc.cpp:825
SettingsManager settingsManager
Definition: settings.cpp:14
static void InVisualRange(const UObject *obj, F &&f)
Definition: uworld.h:245
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:632
void SetRegionLightLevel(LightRegion *lightregion, int lightlevel)
Definition: ufunc.cpp:1676
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:357
u32 GetCurrentItemSerialNumber(void)
Definition: ufunc.cpp:107
StateManager stateManager
Definition: state.cpp:8
void play_object_centered_effect(const UObject *center, u16 effect, u8 speed, u8 loop)
Definition: ufunc.cpp:1078
u16 getamount() const
Definition: item.h:295
void send_item(Client *client, const Item *item)
Definition: ufunc.cpp:676
void send_weather(Client *client, u8 type, u8 severity, u8 aux)
Definition: ufunc.cpp:776
void send_corpse_equip(Client *client, const UCorpse *corpse)
Definition: ufunc.cpp:578
void build_owncreate(const Character *chr, PktOut_78 *owncreate)
Definition: ufunc.cpp:282
void movingEffect(const Core::UObject *src, const Core::UObject *dst, u16 effect, u8 speed, u8 loop, u8 explode)
Definition: packetdefs.cpp:521
bool IsCharacter(u32 serial)
Definition: uobject.h:311
u32 rev() const
Definition: uobject.h:220
ZoneItems items
Definition: uworld.h:72
bool in_yell_range(const Character *c1, const Character *c2)
Definition: ufunc.cpp:508
void send_buff_message(Character *chr, u16 icon, bool show, u16 duration, u32 cl_name, u32 cl_descr, std::vector< u32 > arguments)
Definition: ufunc.cpp:2188
void send_corpse_contents(Client *client, const UCorpse *corpse)
Definition: ufunc.cpp:608
unsigned char support_faces
Definition: ssopt.h:80
u8 slot_index() const
Definition: item.h:358
void subtract_amount_from_item(Item *item, unsigned short amount)
Definition: ufunc.cpp:1584
bool invisible() const
Definition: item.h:324
Core::UContainer * backpack() const
Definition: charactr.cpp:1276
void restart_decay_timer()
Definition: item.cpp:974
void update_weatherregion(Client *client, WeatherRegion *weatherregion)
Definition: ufunc.cpp:1733
unsigned short uo_expansion_flag() const
Definition: account.cpp:235
void setrealmif(Item *item, void *arg)
Definition: ufunc.cpp:1577
bool is_equipped(const Items::Item *item) const
Definition: charactr.cpp:1342
void play_sound_effect_private(const UObject *center, u16 effect, Character *forchr)
Definition: ufunc.cpp:1030
unsigned short pol_distance(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
Definition: ufunc.cpp:481
void send_container_contents(Network::Client *client, const UContainer &cont)
Definition: ufunc2.cpp:78
Realms::Realm * realm
Definition: baseobject.h:56
u32 GetCurrentCharSerialNumber(void)
Definition: ufunc.cpp:113
Items::Item * find_wornitem(u32 find_serial) const
Definition: charactr.cpp:1499
const u16 SA
Definition: client.h:80
unsigned lightlevel
Definition: miscrgn.h:57
ObjectStorageManager objStorageManager
unsigned short width() const
Definition: realm.h:241
void SetCurrentItemSerialNumber(u32 serial)
Definition: ufunc.cpp:95
Items::Item * search_remote_containers(u32 find_serial, bool *isRemoteContainer) const
Definition: charactr.cpp:3996
Core::Zone ** zone
Definition: realm.h:133
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
const VitalValue & vital(unsigned vitalid) const
Definition: charactr.h:1061
void send_wornitem_to_inrange(const Character *chr, const Item *item)
Definition: ufunc.cpp:842
Items::Item * wornitem(int layer) const
Definition: charactr.cpp:1332
void sendCharProfile(Character *chr, Character *of_who, const char *title, const u16 *utext, const u16 *etext)
Definition: ufunc.cpp:2139
unsigned char severity
Definition: miscrgn.h:70
void UpdateCharacterOnDestroyItem(Item *item)
Definition: ufunc.cpp:1927
bool can_move(const Items::Item *item) const
Definition: charactr.cpp:1218
void update_lightregion(Client *client, LightRegion *)
Definition: ufunc.cpp:1668
void send_client_char_data(Mobile::Character *chr, Network::Client *client)
Definition: ufunc.cpp:803
void send_char_data(Client *client, Character *chr)
Definition: ufunc.cpp:787
const MultiDef & multidef() const
Definition: multis.cpp:69
void send_remove_character_to_nearby_cansee(const Character *chr)
Definition: ufunc.cpp:400
u16 wxL
Definition: uworld.h:178
void send_season_info(Client *client)
Definition: ufunc.cpp:2090
bool clientHasCharacter(Client *c)
Definition: ufunc.cpp:1942
#define passert_always(exp)
Definition: passert.h:80
void send_object_cache_to_inrange(const UObject *obj)
Definition: tooltips.cpp:77
bool inrangex(const Character *c1, const Character *c2, int maxdist)
Definition: ufunc.cpp:443
void send_object_cache(Network::Client *client, const UObject *obj)
Definition: tooltips.cpp:68
virtual std::string description() const
Definition: uobject.cpp:201
Multi::UMulti * find_supporting_multi(unsigned short x, unsigned short y, short z) const
Definition: realmfunc.cpp:709
void play_stationary_effect(u16 x, u16 y, s8 z, u16 effect, u8 speed, u8 loop, u8 explode, Realms::Realm *realm)
Definition: ufunc.cpp:1086
void extricate()
Definition: item.cpp:906
bool use_tile_flag_prefix
Definition: ssopt.h:52
void send_owncreate(Client *client, const Character *chr)
Definition: ufunc.cpp:206
Mobile::Character * GetCharacterOwner()
Definition: item.cpp:1168
void send_create_mobile_to_nearby_cansee(const Character *chr)
Definition: ufunc.cpp:1895
void transmit_to_others_inrange(Character *center, const void *msg, unsigned msglen)
Definition: ufunc.cpp:1518
void MoveItemWorldPosition(unsigned short oldx, unsigned short oldy, Items::Item *item, Realms::Realm *oldrealm)
Definition: uworld.cpp:214
void play_moving_effect_ex(const UObject *src, const UObject *dst, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 direction, u8 explode, u16 effect3d, u16 effect3dexplode, u16 effect3dsound)
Definition: ufunc.cpp:1113
void followEffect(const Core::UObject *center, u16 effect, u8 speed, u8 loop)
Definition: packetdefs.cpp:575
bool say_above(const UObject *obj, const char *text, unsigned short font, unsigned short color, unsigned int journal_print)
Definition: ufunc.cpp:1258
void play_lightning_bolt_effect(const UObject *center)
Definition: ufunc.cpp:1070
void send_map_difs(Client *client)
Sends number of maps used and number of map/static patches for each map.
Definition: ufunc.cpp:2044
Definition: berror.cpp:12
bool can_see_on_corpse(const Client *client, const Item *item)
Definition: ufunc.cpp:567
const u16 LBR
Definition: client.h:74
void send_sysmessage(Network::Client *client, const char *text, unsigned short font, unsigned short color)
Definition: ufunc.cpp:1147
void check_light_region_change()
Definition: charactr.cpp:3416
void send_objdesc(Client *client, Item *item)
Definition: ufunc.cpp:1425
void send_put_in_container(Client *client, const Item *item)
Definition: ufunc.cpp:528
void update_item_to_inrange(const Item *item)
Definition: ufunc.cpp:737
UoClientGeneral uoclient_general
Definition: network.h:67
bool invul() const
Definition: charactr.cpp:4080
bool multi_inrange(const Mobile::Character *c1, const Multi::UMulti *obj)
Definition: ufunc.cpp:474