Pol  Revision:cb584c9
dropitem.cpp
Go to the documentation of this file.
1 
28 #include <cstdio>
29 #include <string>
30 
31 #include "../bscript/berror.h"
32 #include "../clib/clib_endian.h"
33 #include "../clib/logfacility.h"
34 #include "../clib/passert.h"
35 #include "../clib/random.h"
36 #include "../clib/rawtypes.h"
37 #include "../plib/systemstate.h"
38 #include "containr.h"
39 #include "eventid.h"
40 #include "fnsearch.h"
41 #include "globals/uvars.h"
42 #include "item/item.h"
43 #include "los.h"
44 #include "mobile/charactr.h"
45 #include "mobile/npc.h"
46 #include "multi/multi.h"
47 #include "network/client.h"
48 #include "network/packetdefs.h"
49 #include "network/packethelper.h"
50 #include "network/packets.h"
51 #include "objtype.h"
52 #include "pktboth.h"
53 #include "pktdef.h"
54 #include "pktin.h"
55 #include "polcfg.h"
56 #include "realms/realm.h"
57 #include "reftypes.h"
58 #include "statmsg.h"
59 #include "storage.h"
60 #include "syshook.h"
61 #include "ufunc.h"
62 #include "uobject.h"
63 #include "uoscrobj.h"
64 #include "uworld.h"
65 
66 namespace Pol
67 {
68 namespace Core
69 {
70 void send_trade_statuses( Mobile::Character* chr );
71 
73  u16 y, u8 slotIndex )
74 {
75  ItemRef itemref( item );
76  if ( ( cont->serial == item->serial ) || is_a_parent( cont, item->serial ) )
77  {
79  return false;
80  }
81 
82  if ( !cont->can_add( *item ) )
83  {
85  send_sysmessage( client, "That item is too heavy for the container or the container is full." );
86  return false;
87  }
88  if ( !cont->can_insert_add_item( client->chr, UContainer::MT_PLAYER, item ) )
89  {
91  return false;
92  }
93 
94  if ( item->orphan() )
95  {
96  return true;
97  }
98 
99  if ( !cont->can_add_to_slot( slotIndex ) )
100  {
102  send_sysmessage( client, "The container has no free slots available!" );
103  return false;
104  }
105  if ( !item->slot_index( slotIndex ) )
106  {
108  send_sysmessage( client, "The container has no free slots available!" );
109  return false;
110  }
111 
112  item->set_dirty();
113 
114  client->pause();
116 
117  item->x = x;
118  item->y = y;
119 
120  cont->add( item );
121  cont->restart_decay_timer();
122  if ( !item->orphan() )
123  {
125 
126  cont->on_insert_add_item( client->chr, UContainer::MT_PLAYER, item );
127  }
128 
129  client->restart();
130  return true;
131 }
132 
134  UContainer* cont, Mobile::Character* dropon, u16 x,
135  u16 y, u8 move_type );
137  u16 y )
138 {
139  UContainer* cont = client->chr->trade_container();
140  Mobile::Character* dropon = client->chr->trading_with.get();
141  if ( dropon == nullptr || dropon->client == nullptr )
142  {
143  send_sysmessage( client, "Unable to complete trade" );
144  return false;
145  }
147  {
149  new Module::ECharacterRefObjImp( dropon ),
150  new Module::EItemRefObjImp( item ) ) )
151  {
153  return false;
154  }
155  }
156  if ( !cont->can_add( *item ) )
157  {
158  send_sysmessage( client, "That's too heavy to trade." );
159  return false;
160  }
161  if ( !cont->can_insert_add_item( client->chr, UContainer::MT_PLAYER, item ) )
162  {
164  return false;
165  }
166 
167  // FIXME : Add Grid Index Default Location Checks here.
168  // Remember, if index fails, move to the ground. That is, IF secure trade uses
169  // grid index.
170 
171  return do_place_item_in_secure_trade_container( client, item, cont, dropon, x, y, 0 );
172 }
173 
175  Items::Item* item )
176 {
177  UContainer* cont = client->chr->trade_container();
178  Mobile::Character* dropon = client->chr->trading_with.get();
179  if ( dropon == nullptr || dropon->client == nullptr )
180  {
181  return new Bscript::BError( "Unable to complete trade" );
182  }
184  {
186  new Module::ECharacterRefObjImp( dropon ),
187  new Module::EItemRefObjImp( item ) ) )
188  {
190  return new Bscript::BError( "Could not insert item into container." );
191  }
192  }
193  if ( !cont->can_add( *item ) )
194  {
195  return new Bscript::BError( "That's too heavy to trade." );
196  }
197  if ( !cont->can_insert_add_item( client->chr, UContainer::MT_CORE_MOVED, item ) )
198  {
200  return new Bscript::BError( "Could not insert item into container." );
201  }
202 
203  // FIXME : Add Grid Index Default Location Checks here.
204  // Remember, if index fails, move to the ground.
205 
207  client, item, cont, dropon, 5 + static_cast<u16>( Clib::random_int( 44 ) ),
208  5 + static_cast<u16>( Clib::random_int( 44 ) ), 1 ) )
209  return new Bscript::BLong( 1 );
210  else
211  return new Bscript::BError( "Something went wrong with trade window." );
212 }
213 
215  UContainer* cont, Mobile::Character* dropon, u16 x,
216  u16 y, u8 move_type )
217 {
218  client->pause();
219 
220  client->chr->trade_accepted( false );
221  dropon->trade_accepted( false );
222  send_trade_statuses( client->chr );
223 
225 
226  item->x = x;
227  item->y = y;
228  item->z = 9;
229 
230  cont->add( item );
231 
232  send_put_in_container( client, item );
233  send_put_in_container( dropon->client, item );
234 
235  if ( move_type == 1 )
236  cont->on_insert_add_item( client->chr, UContainer::MT_CORE_MOVED, item );
237  else
238  cont->on_insert_add_item( client->chr, UContainer::MT_PLAYER, item );
239 
240  send_trade_statuses( client->chr );
241  send_trade_statuses( dropon->client->chr );
242 
243  client->restart();
244  return true;
245 }
246 
247 bool add_item_to_stack( Network::Client* client, Items::Item* item, Items::Item* target_item )
248 {
249  // TJ 3/18/3: Only called (so far) from place_item(), so it's only ever from
250  // a player; this means that there's no need to worry about passing
251  // UContainer::MT_CORE_* constants to the can_insert function (yet). :)
252 
253  ItemRef itemref( item );
254  if ( ( !target_item->stackable() ) || ( !target_item->can_add_to_self( *item, false ) ) ||
255  ( target_item->container &&
256  !target_item->container->can_insert_increase_stack(
257  client->chr, UContainer::MT_PLAYER, target_item, item->getamount(), item ) ) )
258  {
259  send_sysmessage( client, "Could not add item to stack." );
261 
262  return false;
263  }
264 
265  if ( item->orphan() )
266  return false;
267 
268  /* At this point, we know:
269  the object types match
270  the combined stack isn't 'too large'
271  We don't know: (FIXME)
272  if a container that the target_item is in will overfill from this
273  */
274 
276 
277  u16 amtadded = item->getamount();
278 
279  target_item->add_to_self( item );
280  update_item_to_inrange( target_item );
281 
282  if ( target_item->container )
283  {
285  target_item, amtadded );
286  target_item->container->restart_decay_timer();
287  }
288  return true;
289 }
290 
291 bool place_item( Network::Client* client, Items::Item* item, u32 target_serial, u16 x, u16 y,
292  u8 slotIndex )
293 {
294  Items::Item* target_item = find_legal_item( client->chr, target_serial );
295 
296  if ( target_item == nullptr && client->chr->is_trading() )
297  {
298  UContainer* cont = client->chr->trade_container();
299  if ( target_serial == cont->serial )
300  {
301  if ( item->no_drop() )
302  {
304  return false;
305  }
306  return place_item_in_secure_trade_container( client, item, x, y );
307  }
308  }
309 
310  if ( target_item == nullptr )
311  {
313  return false;
314  }
315 
316  if ( ( pol_distance( client->chr, target_item ) > 2 ) && !client->chr->can_moveanydist() )
317  {
319  return false;
320  }
321  if ( !client->chr->realm->has_los( *client->chr, *target_item->toplevel_owner() ) )
322  {
324  return false;
325  }
326 
327 
328  if ( target_item->isa( UOBJ_CLASS::CLASS_ITEM ) )
329  {
330  if ( item->no_drop() )
331  {
332  if ( target_item->container == nullptr || !target_item->container->no_drop_exception() )
333  {
335  return false;
336  }
337  }
338  return add_item_to_stack( client, item, target_item );
339  }
340  else if ( target_item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
341  {
342  if ( item->no_drop() && !( static_cast<UContainer*>( target_item )->no_drop_exception() ) )
343  {
345  return false;
346  }
347  return place_item_in_container( client, item, static_cast<UContainer*>( target_item ), x, y,
348  slotIndex );
349  }
350  else
351  {
352  // UNTESTED CLIENT_HOLE?
354 
355  return false;
356  }
357 }
358 
359 bool drop_item_on_ground( Network::Client* client, Items::Item* item, u16 x, u16 y, s8 z )
360 {
361  if ( item->no_drop() )
362  {
364  return false;
365  }
366 
367  Mobile::Character* chr = client->chr;
368 
369  Multi::UMulti* multi;
370  short newz;
371  if ( !inrangex( chr, x, y, 2 ) && !client->chr->can_moveanydist() )
372  {
373  POLLOG_ERROR.Format( "Client (Character {}) tried to drop an item out of range.\n" )
374  << client->chr->name();
376  return false;
377  }
378 
379  if ( !chr->realm->dropheight( x, y, z, client->chr->z, &newz, &multi ) )
380  {
381  POLLOG_ERROR.Format(
382  "Client (Character {}) tried to drop an item at ({},{},{}), which is a blocked "
383  "location.\n" )
384  << client->chr->name() << x << y << (int)z;
385  return false;
386  }
387 
388  LosObj tgt( x, y, static_cast<s8>( newz ), chr->realm );
389  if ( !chr->realm->has_los( *client->chr, tgt ) )
390  {
392  return false;
393  }
394 
395  item->set_dirty();
396  item->restart_decay_timer();
397  item->x = x;
398  item->y = y;
399  item->z = static_cast<s8>( newz );
400  if ( item->realm != chr->realm )
401  {
402  if ( item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
403  {
404  UContainer* cont = static_cast<UContainer*>( item );
405  cont->for_each_item( setrealm, (void*)chr->realm );
406  }
407  setrealm( item, (void*)chr->realm );
408  }
409  item->container = nullptr;
410  item->reset_slot();
411  add_item_to_world( item );
412  if ( multi != nullptr )
413  {
414  multi->register_object( item );
415  }
416 
417  send_item_to_inrange( item );
418  return true;
419 }
420 
422 {
423  StorageArea* area = gamestate.storage.create_area( "GivenItems" );
424  passert( area != nullptr );
425 
426  for ( unsigned short i = 0; i < 500; ++i )
427  {
428  std::string name = "Cont" + Clib::decint( i );
429  Items::Item* item = nullptr;
430  item = area->find_root_item( name );
431  if ( item == nullptr )
432  {
434  item->setname( name );
435  item->realm = find_realm( std::string( "britannia" ) );
436  area->insert_root_item( item );
437  }
438  // Changed this from a passert to return null.
439  if ( !( item->isa( UOBJ_CLASS::CLASS_CONTAINER ) ) )
440  return nullptr;
441  UContainer* cont = static_cast<UContainer*>( item );
442  if ( !cont->can_add_to_slot( slotIndex ) )
443  {
444  return nullptr;
445  }
446  if ( !item_to_add->slot_index( slotIndex ) )
447  {
448  return nullptr;
449  }
450  if ( cont->can_add( *item_to_add ) )
451  return cont;
452  }
453  return nullptr;
454 }
455 
457 {
458  auto msg =
459  Network::AddItemContainerMsg( cont->serial_ext, cont->graphic, 1 /*amount*/, 0 /*x*/, 0 /*y*/,
460  cont->slot_index(), whos->serial_ext, cont->color );
461  msg.Send( client );
462 }
463 
464 bool do_open_trade_window( Network::Client* client, Items::Item* item, Mobile::Character* dropon );
466 {
467  if ( !Plib::systemstate.config.enable_secure_trading )
468  {
469  send_sysmessage( client, "Secure trading is unavailable." );
470  return false;
471  }
472 
474  {
475  if ( dropon->warmode() )
476  {
477  send_sysmessage( client, "You cannot trade with someone in war mode." );
478  return false;
479  }
480  if ( client->chr->warmode() )
481  {
482  send_sysmessage( client, "You cannot trade while in war mode." );
483  return false;
484  }
485  }
486  if ( dropon->is_trading() )
487  {
488  send_sysmessage( client, "That person is already involved in a trade." );
489  return false;
490  }
491  if ( client->chr->is_trading() )
492  {
493  send_sysmessage( client, "You are already involved in a trade." );
494  return false;
495  }
496  if ( !dropon->client )
497  {
498  send_sysmessage( client, "That person is already involved in a trade." );
499  return false;
500  }
501  if ( client->chr->dead() || dropon->dead() )
502  {
503  send_sysmessage( client, "Ghosts cannot trade items." );
504  return false;
505  }
506 
507  return do_open_trade_window( client, item, dropon );
508 }
509 
511 {
512  if ( !Plib::systemstate.config.enable_secure_trading )
513  {
514  return new Bscript::BError( "Secure trading is unavailable." );
515  }
516 
518  {
519  if ( dropon->warmode() )
520  {
521  return new Bscript::BError( "You cannot trade with someone in war mode." );
522  }
523  if ( client->chr->warmode() )
524  {
525  return new Bscript::BError( "You cannot trade while in war mode." );
526  }
527  }
528  if ( dropon->is_trading() )
529  {
530  return new Bscript::BError( "That person is already involved in a trade." );
531  }
532  if ( client->chr->is_trading() )
533  {
534  return new Bscript::BError( "You are already involved in a trade." );
535  }
536  if ( !dropon->client )
537  {
538  return new Bscript::BError( "That person is already involved in a trade." );
539  }
540  if ( client->chr->dead() || dropon->dead() )
541  {
542  return new Bscript::BError( "Ghosts cannot trade items." );
543  }
544 
545  if ( do_open_trade_window( client, nullptr, dropon ) )
546  return new Bscript::BLong( 1 );
547  else
548  return new Bscript::BError( "Something goes wrong." );
549 }
550 
552 {
553  dropon->create_trade_container();
554  client->chr->create_trade_container();
555 
556  dropon->trading_with.set( client->chr );
557  dropon->trade_accepted( false );
558  client->chr->trading_with.set( dropon );
559  client->chr->trade_accepted( false );
560 
561  send_trade_container( client, dropon, dropon->trade_container() );
562  send_trade_container( dropon->client, dropon, dropon->trade_container() );
563  send_trade_container( client, client->chr, client->chr->trade_container() );
564  send_trade_container( dropon->client, client->chr, client->chr->trade_container() );
565 
567  msg->WriteFlipped<u16>( sizeof msg->buffer );
568  msg->Write<u8>( PKTBI_6F::ACTION_INIT );
569  msg->Write<u32>( dropon->serial_ext );
570  msg->Write<u32>( client->chr->trade_container()->serial_ext );
571  msg->Write<u32>( dropon->trade_container()->serial_ext );
572  msg->Write<u8>( 1u );
573  msg->Write( dropon->name().c_str(), 30, false );
574 
575  msg.Send( client );
576 
577  msg->offset = 4;
578  msg->Write<u32>( client->chr->serial_ext );
579  msg->Write<u32>( dropon->trade_container()->serial_ext );
580  msg->Write<u32>( client->chr->trade_container()->serial_ext );
581  msg->offset++; // u8 havename same as above
582  msg->Write( client->chr->name().c_str(), 30, false );
583  msg.Send( dropon->client );
584 
585  if ( item != nullptr )
586  return place_item_in_secure_trade_container( client, item, 20, 20 );
587  else
588  return true;
589 }
590 
591 bool drop_item_on_mobile( Network::Client* client, Items::Item* item, u32 target_serial,
592  u8 slotIndex )
593 {
594  Mobile::Character* dropon = find_character( target_serial );
595 
596  if ( dropon == nullptr )
597  {
599  return false;
600  }
601 
602  if ( pol_distance( client->chr, dropon ) > 2 && !client->chr->can_moveanydist() )
603  {
605  return false;
606  }
607  if ( !client->chr->realm->has_los( *client->chr, *dropon ) )
608  {
610  return false;
611  }
612 
613  if ( !dropon->isa( UOBJ_CLASS::CLASS_NPC ) )
614  {
615  if ( item->no_drop() )
616  {
618  return false;
619  }
621  {
623  new Module::ECharacterRefObjImp( dropon ),
624  new Module::EItemRefObjImp( item ) ) )
625  {
627  return false;
628  }
629  }
630  bool res = open_trade_window( client, item, dropon );
631  if ( !res )
633  return res;
634  }
635 
636  Mobile::NPC* npc = static_cast<Mobile::NPC*>( dropon );
637  if ( !npc->can_accept_event( EVID_ITEM_GIVEN ) )
638  {
640  return false;
641  }
642  if ( item->no_drop() && !npc->no_drop_exception() )
643  {
645  return false;
646  }
647 
648  UContainer* cont = find_giveitem_container( item, slotIndex );
649  if ( cont == nullptr )
650  {
652  return false;
653  }
654 
655  if ( !cont->can_add_to_slot( slotIndex ) || !item->slot_index( slotIndex ) )
656  {
658  return false;
659  }
660 
661  client->pause();
662 
664 
665  u16 rx, ry;
666  cont->get_random_location( &rx, &ry );
667 
668  item->set_dirty();
669  item->container = cont;
670  item->x = rx;
671  item->y = ry;
672 
673  cont->add_at_random_location( item );
674 
675  npc->send_event( new Module::ItemGivenEvent( client->chr, item, npc ) );
676 
677  client->restart();
678 
679  return true;
680 }
681 
682 // target_serial should indicate a character, or a container, but not a pile.
683 bool drop_item_on_object( Network::Client* client, Items::Item* item, u32 target_serial,
684  u8 slotIndex )
685 {
686  ItemRef itemref( item );
687  UContainer* cont = nullptr;
688  if ( IsCharacter( target_serial ) )
689  {
690  if ( target_serial == client->chr->serial )
691  {
692  cont = client->chr->backpack();
693  }
694  else
695  {
696  return drop_item_on_mobile( client, item, target_serial, slotIndex );
697  }
698  }
699 
700  if ( cont == nullptr )
701  {
702  cont = find_legal_container( client->chr, target_serial );
703  }
704 
705  if ( cont == nullptr )
706  {
708  return false;
709  }
710  if ( item->no_drop() && !cont->no_drop_exception() )
711  {
713  return false;
714  }
715  if ( pol_distance( client->chr, cont ) > 2 && !client->chr->can_moveanydist() )
716  {
718  return false;
719  }
720  if ( !client->chr->realm->has_los( *client->chr, *cont->toplevel_owner() ) )
721  {
723  return false;
724  }
725 
726  if ( item->stackable() )
727  {
728  for ( UContainer::const_iterator itr = cont->begin(); itr != cont->end(); ++itr )
729  {
730  Items::Item* exitem = GET_ITEM_PTR( itr );
731  if ( exitem->can_add_to_self( *item, false ) )
732  {
733  if ( cont->can_add( *item ) )
734  {
735  if ( cont->can_insert_increase_stack( client->chr, UContainer::MT_PLAYER, exitem,
736  item->getamount(), item ) )
737  {
738  if ( item->orphan() )
739  {
740  return true;
741  }
742  u16 amtadded = item->getamount();
743  exitem->add_to_self( item );
744  update_item_to_inrange( exitem );
745 
746  cont->on_insert_increase_stack( client->chr, UContainer::MT_PLAYER, exitem, amtadded );
747 
748  return true;
749  }
750  }
751  return false;
752  }
753  }
754  }
755 
756  u16 rx, ry;
757  cont->get_random_location( &rx, &ry );
758 
759  return place_item_in_container( client, item, cont, rx, ry, slotIndex );
760 }
761 
762 /* DROP_ITEM messages come in a couple varieties:
763 
764  1) Dropping an item on another object, or a person:
765  item_serial: serial number of item to drop
766  x: 0xFFFF
767  y: 0xFFFF
768  z: 0
769  target_serial: serial number of item or character to drop on.
770 
771  2) Dropping an item on the ground:
772  item_serial: serial number of item to drop
773  x,y,z: position
774  target_serial: 0xFFFFFFFF
775 
776  3) Placing an item in a container, or in an existing pile:
777  item_serial: serial number of item to drop
778  x: x-position
779  y: y-position
780  z: 0
781  target_serial: serial number of item or character or pile to drop on.
782  */
783 
784 /*
785  Name: drop_item
786  Details: Original version of packet is supported by this function.
787  Access: public
788  Qualifier:
789  Parameter: Client * client
790  Parameter: PKTIN_08_V1 * msg
791  */
792 void drop_item( Network::Client* client, PKTIN_08_V1* msg )
793 {
794  u32 item_serial = cfBEu32( msg->item_serial );
795  u16 x = cfBEu16( msg->x );
796  u16 y = cfBEu16( msg->y );
797  s8 z = msg->z;
798  u32 target_serial = cfBEu32( msg->target_serial );
799 
800  Items::Item* item = client->chr->gotten_item();
801  if ( item == nullptr )
802  {
803  POLLOG_ERROR.Format(
804  "Character 0x{:X} tried to drop item 0x{:X}, but had not gotten an item.\n" )
805  << client->chr->serial << item_serial;
806  return;
807  }
808  if ( item->serial != item_serial )
809  {
810  POLLOG_ERROR.Format(
811  "Character 0x{:X} tried to drop item 0x{:X}, but instead had gotten item 0x{:X}.\n" )
812  << client->chr->serial << item_serial << item->serial;
813  item->gotten_by( nullptr );
814  return;
815  }
816  item->inuse( false );
817  item->gotten_by( nullptr );
818  client->chr->gotten_item( nullptr );
819 
820  bool res;
821  if ( target_serial == 0xFFffFFffLu )
822  {
823  res = drop_item_on_ground( client, item, x, y, z );
824  }
825  else if ( x == 0xFFFF )
826  {
827  res = drop_item_on_object( client, item, target_serial, 0 );
828  }
829  else
830  {
831  Multi::UMulti* multi = system_find_multi( target_serial );
832 
833  if ( multi != nullptr )
834  res = drop_item_on_ground( client, item, ( multi->x + x ), ( multi->y + y ), z );
835  else
836  res = place_item( client, item, target_serial, x, y, 0 );
837  }
838 
839  if ( !item->orphan() )
840  {
841  if ( !res )
842  {
843  undo_get_item( client->chr, item );
844  }
845  item->inuse( false );
846  item->gotten_by( nullptr );
847  }
848  send_full_statmsg( client, client->chr );
849 }
850 
851 
852 /*
853  Name: drop_item_v2
854  Details: This is used for the version of the packet introduced in clients 6.0.1.7 2D and
855  UO:KR+ to support Slots
856  Access: public
857  Qualifier:
858  Parameter: Client * client
859  Parameter: PKTIN_08_V2 * msg
860  */
862 {
863  u32 item_serial = cfBEu32( msg->item_serial );
864  u16 x = cfBEu16( msg->x );
865  u16 y = cfBEu16( msg->y );
866  s8 z = msg->z;
867  u8 slotIndex = msg->slotindex;
868  u32 target_serial = cfBEu32( msg->target_serial );
869 
870  Items::Item* item = client->chr->gotten_item();
871  if ( item == nullptr )
872  {
873  POLLOG_ERROR.Format(
874  "Character 0x{:X} tried to drop item 0x{:X}, but had not gotten an item.\n" )
875  << client->chr->serial << item_serial;
876  return;
877  }
878  if ( item->serial != item_serial )
879  {
880  POLLOG_ERROR.Format(
881  "Character 0x{:X} tried to drop item 0x{:X}, but instead had gotten item 0x{:X}.\n" )
882  << client->chr->serial << item_serial << item->serial;
883  item->gotten_by( nullptr );
884  return;
885  }
886  item->inuse( false );
887  item->gotten_by( nullptr );
888  client->chr->gotten_item( nullptr );
889 
890  bool res;
891  if ( target_serial == 0xFFffFFffLu )
892  {
893  res = drop_item_on_ground( client, item, x, y, z );
894  }
895  else if ( x == 0xFFFF )
896  {
897  res = drop_item_on_object( client, item, target_serial, slotIndex );
898  }
899  else
900  {
901  Multi::UMulti* multi = system_find_multi( target_serial );
902 
903  if ( multi != nullptr )
904  res = drop_item_on_ground( client, item, ( multi->x + x ), ( multi->y + y ), z );
905  else
906  res = place_item( client, item, target_serial, x, y, 0 );
907  }
908 
909  if ( !item->orphan() )
910  {
911  if ( !res )
912  {
913  undo_get_item( client->chr, item );
914  }
915  item->inuse( false );
916  item->gotten_by( nullptr );
917  }
918 
920  drop_msg.Send( client );
921 
922  send_full_statmsg( client, client->chr );
923 }
924 
926 {
927  UContainer* cont = chr->trade_container();
928  UContainer* bp = chr->backpack();
929  if ( cont == nullptr || bp == nullptr )
930  return;
931 
933  cont->extract( tmp );
934  while ( !tmp.empty() )
935  {
936  Items::Item* item = ITEM_ELEM_PTR( tmp.back() );
937  tmp.pop_back();
938  item->container = nullptr;
939  item->layer = 0;
940 
941  ItemRef itemref( item );
942  if ( bp->can_add( *item ) && bp->can_insert_add_item( chr, UContainer::MT_CORE_MOVED, item ) )
943  {
944  if ( item->orphan() )
945  {
946  continue;
947  }
948  u8 newSlot = 1;
949  if ( !bp->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
950  {
951  item->set_dirty();
952  item->x = chr->x;
953  item->y = chr->y;
954  item->z = chr->z;
955  add_item_to_world( item );
957  move_item( item, item->x, item->y, item->z, nullptr );
958  return;
959  }
960  bp->add_at_random_location( item );
961  if ( chr->client )
962  send_put_in_container( chr->client, item );
964  }
965  else
966  {
967  item->set_dirty();
968  item->x = chr->x;
969  item->y = chr->y;
970  item->realm = chr->realm;
971  add_item_to_world( item );
973  move_item( item, chr->x, chr->y, chr->z, nullptr );
974  }
975  }
976 }
977 
978 
980 {
981  Mobile::Character* chr2 = chr1->trading_with.get();
982 
983  return_traded_items( chr1 );
984  chr1->trading_with.clear();
985 
986  if ( chr1->client )
987  {
989  msg->WriteFlipped<u16>( 17u ); // no name
990  msg->Write<u8>( PKTBI_6F::ACTION_CANCEL );
991  msg->Write<u32>( chr1->trade_container()->serial_ext );
992  msg->offset += 9; // u32 cont1_serial, cont2_serial, u8 havename
993  msg.Send( chr1->client );
994  send_full_statmsg( chr1->client, chr1 );
995  }
996 
997  if ( chr2 )
998  {
999  return_traded_items( chr2 );
1000  chr2->trading_with.clear();
1001  if ( chr2->client )
1002  {
1004  msg->WriteFlipped<u16>( 17u ); // no name
1005  msg->Write<u8>( PKTBI_6F::ACTION_CANCEL );
1006  msg->Write<u32>( chr2->trade_container()->serial_ext );
1007  msg->offset += 9; // u32 cont1_serial, cont2_serial, u8 havename
1008  msg.Send( chr2->client );
1009  send_full_statmsg( chr2->client, chr2 );
1010  }
1011  }
1012 }
1013 
1015 {
1016  unsigned int stat1 = chr->trade_accepted() ? 1 : 0;
1017  unsigned int stat2 = chr->trading_with->trade_accepted() ? 1 : 0;
1018 
1020  msg->WriteFlipped<u16>( 17u ); // no name
1021  msg->Write<u8>( PKTBI_6F::ACTION_STATUS );
1022  msg->Write<u32>( chr->trade_container()->serial_ext );
1023  msg->WriteFlipped<u32>( stat1 );
1024  msg->WriteFlipped<u32>( stat2 );
1025  msg->offset++; // u8 havename
1026  Network::transmit( chr->client, &msg->buffer, msg->offset );
1027  msg->offset = 4;
1028  msg->Write<u32>( chr->trading_with->trade_container()->serial_ext );
1029  msg->WriteFlipped<u32>( stat2 );
1030  msg->WriteFlipped<u32>( stat1 );
1031  msg->offset++;
1032  msg.Send( chr->trading_with->client );
1033 }
1034 
1036 {
1037  chr->trade_accepted( set );
1038  send_trade_statuses( chr );
1039  if ( chr->trade_accepted() && chr->trading_with->trade_accepted() )
1040 
1041  {
1042  UContainer* cont0 = chr->trade_container();
1043  UContainer* cont1 = chr->trading_with->trade_container();
1044  if ( cont0->can_swap( *cont1 ) )
1045  {
1046  cont0->swap( *cont1 );
1047  cancel_trade( chr );
1048  }
1049  else
1050  {
1051  POLLOG_ERROR.Format( "Can't swap trade containers: ic0={},w0={}, ic1={},w1={}\n" )
1052  << cont0->item_count() << cont0->weight() << cont1->item_count() << cont1->weight();
1053  }
1054  }
1055 }
1056 
1058 {
1059  if ( !client->chr->is_trading() )
1060  return;
1061  switch ( msg->action )
1062  {
1064  INFO_PRINT_TRACE( 5 ) << "Cancel secure trade\n";
1065  cancel_trade( client->chr );
1066  break;
1067 
1069  bool set;
1070  set = msg->cont1_serial ? true : false;
1071  if ( set )
1072  {
1073  INFO_PRINT_TRACE( 5 ) << "Set secure trade indicator\n";
1074  }
1075  else
1076  {
1077  INFO_PRINT_TRACE( 5 ) << "Clear secure trade indicator\n";
1078  }
1079  change_trade_status( client->chr, set );
1080  break;
1081 
1082  default:
1083  INFO_PRINT_TRACE( 5 ) << "Unknown secure trade action: " << (int)msg->action << "\n";
1084  break;
1085  }
1086 }
1087 
1089 {
1090  for ( auto& client : networkManager.clients )
1091  {
1092  if ( client->ready && client->chr )
1093  {
1094  Mobile::Character* chr = client->chr;
1095  if ( chr->is_trading() )
1096  cancel_trade( chr );
1097  }
1098  }
1099 }
1100 }
1101 }
bool place_item(Network::Client *client, Items::Item *item, u32 target_serial, u16 x, u16 y, u8 slotIndex)
Definition: dropitem.cpp:291
virtual void on_insert_add_item(Mobile::Character *mob, MoveType move, Items::Item *new_item)
Definition: containr.cpp:833
Contents::const_iterator const_iterator
Definition: containr.h:115
unsigned char u8
Definition: rawtypes.h:25
void register_with_supporting_multi(Item *item)
Definition: ufunc.cpp:1875
std::vector< Items::Item * > Contents
Definition: containr.h:113
bool can_accept_event(Core::EVENTID eventid)
Definition: npc.cpp:877
static Item * create(u32 objtype, u32 serial=0)
Definition: itemcr.cpp:53
bool can_add_to_slot(u8 &slotIndex)
Definition: containr.cpp:178
bool can_moveanydist() const
Definition: charactr.cpp:1256
void handle_secure_trade_msg(Network::Client *client, PKTBI_6F *msg)
Definition: dropitem.cpp:1057
bool can_add_to_self(unsigned short amount, bool force_stacking) const
Definition: item.cpp:703
bool allow_secure_trading_in_warmode
Definition: ssopt.h:42
virtual bool can_add(const Items::Item &item) const
Definition: containr.cpp:168
void add_item_to_world(Items::Item *item)
Definition: uworld.cpp:31
bool stackable() const
Definition: item.cpp:570
bool send_event(Bscript::BObjectImp *event)
Definition: npc.cpp:887
SystemState systemstate
Definition: systemstate.cpp:12
bool call(Bscript::BObjectImp *p0)
Definition: syshook.cpp:44
Network::Client * client
Definition: charactr.h:871
bool place_item_in_container(Network::Client *client, Items::Item *item, UContainer *cont, u16 x, u16 y, u8 slotIndex)
Definition: dropitem.cpp:72
UContainer * find_giveitem_container(Items::Item *item_to_add, u8 slotIndex)
Definition: dropitem.cpp:421
virtual UObject * toplevel_owner() POL_OVERRIDE
Definition: item.cpp:252
void extract(Contents &cnt)
Definition: containr.cpp:322
void cancel_all_trades()
Definition: dropitem.cpp:1088
#define cfBEu32(x)
Definition: clib_endian.h:43
SystemHooks system_hooks
Definition: uvars.h:190
std::string decint(unsigned short v)
Definition: strutil.cpp:64
StorageArea * create_area(const std::string &name)
Definition: storage.cpp:144
bool drop_item_on_object(Network::Client *client, Items::Item *item, u32 target_serial, u8 slotIndex)
Definition: dropitem.cpp:683
Item * find_legal_item(const Character *chr, u32 serial, bool *additlegal, bool *isRemoteContainer)
Definition: ufunc.cpp:958
void change_trade_status(Mobile::Character *chr, bool set)
Definition: dropitem.cpp:1035
void transmit(Client *client, const void *data, int len)
Definition: clientio.cpp:291
virtual void register_object(UObject *obj)
Definition: multis.cpp:60
#define POLLOG_ERROR
Definition: logfacility.h:207
void send_trade_container(Network::Client *client, Mobile::Character *whos, UContainer *cont)
Definition: dropitem.cpp:456
void send_put_in_container_to_inrange(const Item *item)
Definition: ufunc.cpp:539
void add_to_self(Item *&item)
Definition: item.cpp:600
virtual void add(Items::Item *item)
Definition: containr.cpp:194
bool can_swap(const UContainer &cont) const
Definition: containr.cpp:328
void send_item_to_inrange(const Item *item)
Definition: ufunc.cpp:706
void swap(UContainer &cont)
Definition: containr.cpp:340
Mobile::Character * chr
Definition: client.h:182
#define MOVE_ITEM_FAILURE_TOO_FAR_AWAY
Definition: pktdef.h:30
#define ITEM_ELEM_PTR(elem)
Definition: containr.h:39
void send_item_move_failure(Network::Client *client, u8 reason)
Definition: ufunc.cpp:818
void undo_get_item(Mobile::Character *chr, Items::Item *item)
Definition: getitem.cpp:260
void set_dirty()
Definition: uobject.h:291
bool no_drop() const
Definition: item.cpp:310
unsigned short u16
Definition: rawtypes.h:26
void send_trade_statuses(Mobile::Character *chr)
Definition: dropitem.cpp:1014
unsigned int u32
Definition: rawtypes.h:27
void get_random_location(u16 *px, u16 *py) const
Definition: containr.cpp:712
Core::UContainer * trade_container()
Definition: charactr.cpp:4142
Multi::UMulti * system_find_multi(u32 serial)
Definition: fnsearch.cpp:50
bool warmode() const
Definition: charactr.cpp:3067
bool drop_item_on_mobile(Network::Client *client, Items::Item *item, u32 target_serial, u8 slotIndex)
Definition: dropitem.cpp:591
void drop_item(Network::Client *client, PKTIN_08_V1 *msg)
Definition: dropitem.cpp:792
virtual unsigned int weight() const POL_OVERRIDE
Definition: containr.cpp:230
NetworkManager networkManager
Definition: network.cpp:28
bool drop_item_on_ground(Network::Client *client, Items::Item *item, u16 x, u16 y, s8 z)
Definition: dropitem.cpp:359
bool is_a_parent(const Item *item, u32 serial)
Definition: ufunc.cpp:877
int random_int(int i)
Definition: random.cpp:34
void Send(Client *client, int len=-1) const
Definition: packethelper.h:69
Core::CharacterRef trading_with
Definition: charactr.h:857
bool orphan() const
Definition: baseobject.h:119
bool has_los(const Core::ULWObject &att, const Core::ULWObject &tgt) const
Definition: realmlos.cpp:146
bool is_trading() const
Definition: charactr.cpp:4117
#define MOVE_ITEM_FAILURE_UNKNOWN
Definition: pktdef.h:38
UContainer * find_legal_container(const Character *chr, u32 serial)
Definition: ufunc.cpp:892
#define passert(exp)
Definition: passert.h:62
void setrealm(Item *item, void *arg)
Definition: ufunc.cpp:1571
void on_insert_increase_stack(Mobile::Character *mob, MoveType move, Items::Item *existing_item, unsigned short amt_added)
Definition: containr.cpp:805
#define cfBEu16(x)
Definition: clib_endian.h:44
signed char s8
Definition: rawtypes.h:29
void add_at_random_location(Items::Item *item)
Definition: containr.cpp:291
Core::UContainer * container
Definition: item.h:256
#define UOBJ_BACKPACK
Definition: objtype.h:202
#define GET_ITEM_PTR(itr)
Definition: containr.h:38
void setname(const std::string &)
Definition: uobject.cpp:206
GameState gamestate
Definition: uvars.cpp:74
void send_remove_object_to_inrange(const UObject *centerObject)
Definition: ufunc.cpp:428
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
Mobile::Character * find_character(u32 serial)
Definition: fnsearch.cpp:60
ExportedFunction * can_trade
Definition: syshook.h:83
void move_item(Item *item, UFACING facing)
Definition: ufunc.cpp:1601
SettingsManager settingsManager
Definition: settings.cpp:14
bool dropheight(unsigned short dropx, unsigned short dropy, short dropz, short chrz, short *newz, Multi::UMulti **pmulti)
Definition: realmfunc.cpp:515
virtual unsigned int item_count() const POL_OVERRIDE
Definition: containr.cpp:235
ref_ptr< Items::Item > ItemRef
Definition: reftypes.h:43
u16 getamount() const
Definition: item.h:295
bool IsCharacter(u32 serial)
Definition: uobject.h:311
#define MOVE_ITEM_FAILURE_OUT_OF_SIGHT
Definition: pktdef.h:31
u8 slot_index() const
Definition: item.h:358
Core::UContainer * backpack() const
Definition: charactr.cpp:1276
void restart_decay_timer()
Definition: item.cpp:974
bool no_drop_exception() const
Definition: containr.cpp:959
#define INFO_PRINT_TRACE(n)
Definition: logfacility.h:226
unsigned short pol_distance(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
Definition: ufunc.cpp:481
Realms::Realm * realm
Definition: baseobject.h:56
void insert_root_item(Items::Item *item)
Definition: storage.cpp:89
bool place_item_in_secure_trade_container(Network::Client *client, Items::Item *item, u16 x, u16 y)
Definition: dropitem.cpp:136
Realms::Realm * find_realm(const std::string &name)
Definition: realms.cpp:64
std::string name
Definition: osmod.cpp:943
bool open_trade_window(Network::Client *client, Items::Item *item, Mobile::Character *dropon)
Definition: dropitem.cpp:465
bool can_insert_increase_stack(Mobile::Character *mob, MoveType move, Items::Item *existing_item, unsigned short amt_to_add, Items::Item *adding_item)
Definition: containr.cpp:787
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
void return_traded_items(Mobile::Character *chr)
Definition: dropitem.cpp:925
void drop_item_v2(Network::Client *client, PKTIN_08_V2 *msg)
Definition: dropitem.cpp:861
bool no_drop_exception() const
Definition: npc.cpp:1058
bool inuse() const
Definition: item.h:314
void reset_slot()
Definition: item.h:363
bool inrangex(const Character *c1, const Character *c2, int maxdist)
Definition: ufunc.cpp:443
virtual std::string name() const
Definition: uobject.cpp:196
bool trade_accepted() const
Definition: charactr.cpp:4122
void cancel_trade(Mobile::Character *chr1)
Definition: dropitem.cpp:979
Storage storage
Definition: uvars.h:156
Definition: berror.cpp:12
bool do_place_item_in_secure_trade_container(Network::Client *client, Items::Item *item, UContainer *cont, Mobile::Character *dropon, u16 x, u16 y, u8 move_type)
Definition: dropitem.cpp:214
bool do_open_trade_window(Network::Client *client, Items::Item *item, Mobile::Character *dropon)
Definition: dropitem.cpp:551
bool dead() const
Definition: charactr.h:931
void send_sysmessage(Network::Client *client, const char *text, unsigned short font, unsigned short color)
Definition: ufunc.cpp:1147
void send_put_in_container(Client *client, const Item *item)
Definition: ufunc.cpp:528
Items::Item * find_root_item(const std::string &name)
Definition: storage.cpp:65
void update_item_to_inrange(const Item *item)
Definition: ufunc.cpp:737
bool add_item_to_stack(Network::Client *client, Items::Item *item, Items::Item *target_item)
Definition: dropitem.cpp:247
virtual void for_each_item(void(*f)(Item *item, void *a), void *arg)
Definition: containr.cpp:659
bool can_insert_add_item(Mobile::Character *mob, MoveType move, Items::Item *new_item)
Definition: containr.cpp:817