Pol  Revision:cb584c9
getitem.cpp
Go to the documentation of this file.
1 
16 #include "getitem.h"
17 
18 #include <cstdio>
19 
20 #include "../clib/clib_endian.h"
21 #include "../clib/rawtypes.h"
22 #include "containr.h"
23 #include "item/item.h"
24 #include "mobile/charactr.h"
25 #include "network/client.h"
26 #include "pktdef.h"
27 #include "pktin.h"
28 #include "reftypes.h"
29 #include "statmsg.h"
30 #include "ufunc.h"
31 #include "uobject.h"
32 #include "uworld.h"
33 
34 
35 /* How get_item works:
36  when the client drags an item off the ground,
37  a GET_ITEM message is generated.
38  when this item is dropped on the paperdoll,
39  an EQUIP_ITEM message is generated.
40  when this item is dropped on the ground,
41  a DROP_ITEM message is generated
42  when this item is placed in a container,
43  a DROP_ITEM message is generated.
44 
45 
46  if the item requested cannot be 'gotten', a ITEM_MOVE_FAILURE message is sent (0x27),
47  reason code 0 (you cannot pick that up). The client automatically places the
48  item back where it was. (what do the real servers do?)
49 
50  if on equip, the item cannot be placed, an ITEM_MOVE_FAILURE(0x27,0x05) is sent.
51  the client just beeps, and does not release the object.
52 
53 */
54 namespace Pol
55 {
56 namespace Core
57 {
58 void get_item( Network::Client* client, PKTIN_07* msg )
59 {
60  u32 serial = cfBEu32( msg->serial );
61  u16 amount = cfBEu16( msg->amount );
62 
63  Items::Item* item;
64 
65  if ( client->chr->has_gotten_item() )
66  {
68  return;
69  }
70  if ( client->chr->dead() )
71  {
73  return;
74  }
75  // try to find the item the client referenced, in all the legal places it might be.
76 
77  bool inRemoteContainer = false, isRemoteContainer = false;
78  item = find_legal_item( client->chr, serial, &inRemoteContainer, &isRemoteContainer );
79  if ( item == nullptr || isRemoteContainer )
80  {
82  return;
83  }
84  ItemRef itemref( item ); // dave 1/28/3 prevent item from being destroyed before function ends
85 
86  u8 oldSlot = item->slot_index();
87 
88  if ( pol_distance( client->chr, item ) > 2 && !client->chr->can_moveanydist() )
89  {
91  return;
92  }
93  if ( !client->chr->realm->has_los( *client->chr, *( item->toplevel_owner() ) ) )
94  {
96  return;
97  }
98  if ( item->inuse() )
99  {
100  send_sysmessage( client, "That is already being used." );
102  return;
103  }
104 
105  if ( !client->chr->can_move( item ) )
106  {
107  send_sysmessage( client, "You cannot move that." );
109  return;
110  }
111 
112  if ( !item->check_unequiptest_scripts() || !item->check_unequip_script() )
113  {
114  send_sysmessage( client, "You cannot unequip that." );
116  return;
117  }
118  if ( item->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
119  {
120  return;
121  }
122 
123  if ( item->container )
124  {
125  if ( !item->container->check_can_remove_script( client->chr, item ) )
126  {
128  return;
129  }
130  if ( item->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
131  {
132  return;
133  }
134  }
135 
136  UObject* my_owner = item->toplevel_owner();
137 
139 
140  UContainer* orig_container = item->container;
141  u16 orig_x = item->x, orig_y = item->y;
142  s8 orig_z = item->z;
143 
144  if ( item->container != nullptr )
145  {
146  if ( IsCharacter( item->container->serial ) )
148  else
150  item->extricate();
151  }
152  else
153  {
155  remove_item_from_world( item );
156  }
157 
158  client->chr->gotten_item( item );
159  item->inuse( true );
160  item->gotten_by( client->chr );
161  item->x = item->y = item->z = 0; // don't let a boat carry it around
162 
163  if ( orig_container != nullptr )
164  {
165  orig_container->on_remove( client->chr, item );
166  if ( item->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
167  {
168  return;
169  }
170  }
171 
172  /* Check for moving part of a stack. Here are the possibilities:
173  1) Client specified more amount than was in the stack.
174  2) Client specified exactly what was in the stack.
175  These are handled identically. The amount specified is ignored, and
176  the item is effectively treated as normal unstackable atomic object.
177  (the stack is moved as a whole)
178  3) Client specified less than is in the stack.
179  In this case, a new object is created at the same location as the old object,
180  with the balance of the amount not removed.
181  */
182  if ( item->amount_to_remove_is_partial( amount ) )
183  {
184  Items::Item* new_item = item->slice_stacked_item( amount );
185  if ( new_item != nullptr )
186  {
187  new_item->restart_decay_timer();
188  new_item->x = orig_x;
189  new_item->y = orig_y;
190  new_item->z = orig_z;
191  if ( orig_container != nullptr )
192  {
193  // NOTE: we just removed 'item' from its container,
194  // so there's room for new_item.
195  if ( !orig_container->can_add_to_slot( oldSlot ) || !item->slot_index( oldSlot ) )
196  {
197  new_item->set_dirty();
198  new_item->x = client->chr->x;
199  new_item->y = client->chr->y;
200  new_item->z = client->chr->z;
201  add_item_to_world( new_item );
202  register_with_supporting_multi( new_item );
203  move_item( new_item, new_item->x, new_item->y, new_item->z, nullptr );
204  }
205  else
206  {
207  orig_container->add( new_item );
209  }
210  }
211  else
212  {
213  add_item_to_world( new_item );
214  register_with_supporting_multi( new_item );
215  send_item_to_inrange( new_item );
216  }
217  }
218  }
219  else
220  {
221  item->set_decay_after( 60 );
222  }
223 
224  // FIXME : Are these all the possibilities for sources and updating, correctly?
226  {
227  // Item was on the ground, so we ONLY need to update the character's weight
228  // to the client.
229  send_full_statmsg( client, client->chr );
230  }
232  {
233  // Item was equipped, let's send the full update for ar and statmsg.
234  client->chr->refresh_ar();
235  }
236  else if ( my_owner->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
237  {
238  // Toplevel owner was a container (not a character). Only update weight.
239  send_full_statmsg( client, client->chr );
240  }
241  else if ( ( my_owner->ismobile() ) && my_owner->serial != client->chr->serial )
242  {
243  // Toplevel was a mob. Make sure mob was not us. If it's not, send update to weight.
244  send_full_statmsg( client, client->chr );
245  }
246 }
247 
248 
249 /*
250  undo_get_item:
251  when a client issues a get_item command, the item is moved into gotten_items.
252  all other clients are told to delete it, so they no longer have access to it.
253  when the client finally tries to do something with it, if that fails, the
254  object must be put back where it was.
255  Sometimes, (ie trying to equip) the client just beeps, and keeps holding onto
256  the item. In those cases, this function is not called but rather the item
257  is replaced in gotten_items, for a later EQUIP_ITEM message.
258  */
259 
261 {
262  // item needs to be returned to where it was.. either on
263  // the ground, or equipped on the current character,
264  // or in whatever it used to be in.
265  ItemRef itemref( item ); // dave 1/28/3 prevent item from being destroyed before function ends
266  item->restart_decay_timer(); // MuadDib: moved to top to help with instant decay.
267 
268  item->gotten_by( nullptr );
270  {
271  if ( chr->equippable( item ) && item->check_equiptest_scripts( chr ) &&
272  item->check_equip_script( chr, false ) )
273  {
274  if ( item->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
275  {
276  return;
277  }
278  // is it possible the character doesn't exist? no, it's my character doing the undoing.
279  chr->equip( item );
280  send_wornitem_to_inrange( chr, item );
281  return;
282  }
283  if ( item->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
284  {
285  return;
286  }
288  }
289 
291  {
292  // First attempt to put it back in the original container.
293  // NOTE: This is lost somewhere before it gets here and so never happens.
294  u8 newSlot = 1;
295  UContainer* orig_container = item->container;
296  if ( orig_container && orig_container->can_insert_add_item( chr, UContainer::MT_PLAYER, item ) )
297  {
298  if ( item->orphan() )
299  {
300  return;
301  }
302  else if ( orig_container->is_legal_posn( item, item->x, item->y ) )
303  {
304  if ( !orig_container->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
305  {
306  item->set_dirty();
307  item->x = chr->x;
308  item->y = chr->y;
309  item->z = chr->z;
310  add_item_to_world( item );
312  move_item( item, chr->x, chr->y, chr->z, nullptr );
313  return;
314  }
315  else
316  orig_container->add( item );
317  }
318  else
319  {
320  if ( !orig_container->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
321  {
322  item->set_dirty();
323  item->x = chr->x;
324  item->y = chr->y;
325  item->z = chr->z;
326  add_item_to_world( item );
328  move_item( item, chr->x, chr->y, chr->z, nullptr );
329  return;
330  }
331  else
332  orig_container->add_at_random_location( item );
333  }
334  update_item_to_inrange( item );
335  orig_container->on_insert_add_item( chr, UContainer::MT_PLAYER, item );
336  return;
337  }
338 
339  // Attempt to place the item in the player's backpack.
340  UContainer* bp = chr->backpack();
341  if ( bp != nullptr && bp->can_add( *item ) &&
342  bp->can_insert_add_item( chr, UContainer::MT_PLAYER, item ) )
343  {
344  if ( item->orphan() )
345  return;
346  else if ( bp->is_legal_posn( item, item->x, item->y ) )
347  {
348  // NOTE it's never in a legal position, cause we clear the x/y/z in getitem
349  if ( !bp->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
350  {
351  item->set_dirty();
352  item->x = chr->x;
353  item->y = chr->y;
354  item->z = chr->z;
355  add_item_to_world( item );
357  move_item( item, chr->x, chr->y, chr->z, nullptr );
358  return;
359  }
360  else
361  bp->add( item );
362  }
363  else
364  {
365  if ( !bp->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
366  {
367  item->set_dirty();
368  item->x = chr->x;
369  item->y = chr->y;
370  item->z = chr->z;
371  add_item_to_world( item );
373  move_item( item, chr->x, chr->y, chr->z, nullptr );
374  return;
375  }
376  else
377  bp->add_at_random_location( item );
378  }
379  update_item_to_inrange( item );
380  bp->on_insert_add_item( chr, UContainer::MT_PLAYER, item );
381  return;
382  }
383  }
384 
385  // Last resort - put it at the player's feet.
386  item->set_dirty();
387  item->x = chr->x;
388  item->y = chr->y;
389  item->z = chr->z;
390  item->realm = chr->realm;
391  item->container = nullptr;
392  // 12-17-2008 MuadDib added to clear item.layer properties.
393  item->layer = 0;
394 
395  add_item_to_world( item );
396 
398  send_item_to_inrange( item );
399 }
400 }
401 }
virtual void on_insert_add_item(Mobile::Character *mob, MoveType move, Items::Item *new_item)
Definition: containr.cpp:833
void on_remove(Mobile::Character *chr, Items::Item *item, MoveType move=MT_PLAYER)
Definition: containr.cpp:769
unsigned char u8
Definition: rawtypes.h:25
void register_with_supporting_multi(Item *item)
Definition: ufunc.cpp:1875
bool can_add_to_slot(u8 &slotIndex)
Definition: containr.cpp:178
bool can_moveanydist() const
Definition: charactr.cpp:1256
bool is_legal_posn(const Items::Item *item, u16 x, u16 y) const
Definition: containr.cpp:733
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 check_unequip_script()
Definition: item.cpp:1064
virtual UObject * toplevel_owner() POL_OVERRIDE
Definition: item.cpp:252
bool check_unequiptest_scripts(Mobile::Character *chr)
Definition: item.cpp:1142
#define cfBEu32(x)
Definition: clib_endian.h:43
bool ismobile() const
Definition: baseobject.h:104
Item * find_legal_item(const Character *chr, u32 serial, bool *additlegal, bool *isRemoteContainer)
Definition: ufunc.cpp:958
enum Pol::Mobile::Character::GOTTEN_ITEM_TYPE gotten_item_source
#define MOVE_ITEM_FAILURE_ALREADY_HOLDING_AN_ITEM
Definition: pktdef.h:33
void send_put_in_container_to_inrange(const Item *item)
Definition: ufunc.cpp:539
virtual void add(Items::Item *item)
Definition: containr.cpp:194
void remove_item_from_world(Items::Item *item)
Definition: uworld.cpp:41
void send_item_to_inrange(const Item *item)
Definition: ufunc.cpp:706
Mobile::Character * chr
Definition: client.h:182
#define MOVE_ITEM_FAILURE_TOO_FAR_AWAY
Definition: pktdef.h:30
void get_item(Network::Client *client, PKTIN_07 *msg)
Definition: getitem.cpp:58
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
unsigned short u16
Definition: rawtypes.h:26
unsigned int u32
Definition: rawtypes.h:27
bool check_equip_script(Mobile::Character *chr, bool startup)
Definition: item.cpp:1051
void set_decay_after(unsigned int seconds)
Definition: item.cpp:954
bool orphan() const
Definition: baseobject.h:119
bool has_los(const Core::ULWObject &att, const Core::ULWObject &tgt) const
Definition: realmlos.cpp:146
#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
void send_remove_object_to_inrange(const UObject *centerObject)
Definition: ufunc.cpp:428
void send_full_statmsg(Network::Client *client, Mobile::Character *chr)
Definition: statmsg.cpp:32
void equip(Items::Item *item)
Definition: charactr.cpp:1433
void move_item(Item *item, UFACING facing)
Definition: ufunc.cpp:1601
ref_ptr< Items::Item > ItemRef
Definition: reftypes.h:43
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
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
bool check_can_remove_script(Mobile::Character *chr, Items::Item *item, MoveType move=MT_PLAYER)
Definition: containr.cpp:848
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
void send_wornitem_to_inrange(const Character *chr, const Item *item)
Definition: ufunc.cpp:842
bool check_equiptest_scripts(Mobile::Character *chr, bool startup=false)
Definition: item.cpp:1137
bool amount_to_remove_is_partial(u16 amount_to_remove) const
Definition: item.cpp:768
virtual void refresh_ar()
Definition: charactr.cpp:2484
Item * slice_stacked_item(u16 this_item_new_amount)
Definition: item.cpp:790
bool can_move(const Items::Item *item) const
Definition: charactr.cpp:1218
bool inuse() const
Definition: item.h:314
bool equippable(const Items::Item *item) const
Definition: charactr.cpp:1356
void extricate()
Definition: item.cpp:906
#define MOVE_ITEM_FAILURE_CANNOT_PICK_THAT_UP
Definition: pktdef.h:29
Definition: berror.cpp:12
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 update_item_to_inrange(const Item *item)
Definition: ufunc.cpp:737
bool can_insert_add_item(Mobile::Character *mob, MoveType move, Items::Item *new_item)
Definition: containr.cpp:817