Pol  Revision:cb584c9
item.cpp
Go to the documentation of this file.
1 
13 #include "item.h"
14 
15 #include <exception>
16 
17 #include "../../bscript/berror.h"
18 #include "../../bscript/eprog.h"
19 #include "../../clib/cfgelem.h"
20 #include "../../clib/passert.h"
21 #include "../../clib/refptr.h"
22 #include "../../clib/streamsaver.h"
23 #include "../../plib/mapcell.h"
24 #include "../../plib/systemstate.h"
25 #include "../clidata.h"
26 #include "../containr.h"
27 #include "../gameclck.h"
28 #include "../globals/uvars.h"
29 #include "../mobile/charactr.h"
30 #include "../network/client.h"
31 #include "../objtype.h"
32 #include "../polcfg.h"
33 #include "../proplist.h"
34 #include "../resource.h"
35 #include "../scrdef.h"
36 #include "../scrsched.h"
37 #include "../scrstore.h"
38 #include "../tooltips.h"
39 #include "../ufunc.h"
40 #include "../uoscrobj.h"
41 #include "itemdesc.h"
42 
43 
44 namespace Pol
45 {
46 namespace Items
47 {
48 const u32 Item::SELLPRICE_DEFAULT = UINT_MAX;
49 const u32 Item::BUYPRICE_DEFAULT = UINT_MAX;
50 
56 Item* Item::clone() const
57 {
58  Item* item = Item::create( objtype_ );
59  item->color = color;
60  item->graphic = graphic;
61  item->x = x;
62  item->y = y;
63  item->z = z;
64  item->realm = realm;
65  item->facing = facing;
66  item->setamount( amount_ );
67  item->layer = layer;
68  item->tile_layer = tile_layer;
69  item->container = nullptr; // was container
70  item->sellprice_( sellprice_() );
71  item->buyprice_( buyprice_() );
72  item->newbie( newbie() );
73  item->insured( insured() );
74 
75  item->invisible( invisible() ); // dave 12-20
76  item->movable( movable() ); // dave 12-20
77  item->hp_ = hp_;
78  item->setQuality( getQuality() );
79 
80  item->on_use_script_ = on_use_script_; // dave 12-20
81  item->equip_script_ = equip_script_; // dave 12-20
82  item->unequip_script_ = unequip_script_; // dave 12-20
83 
84  item->name_ = name_;
85  item->increv();
86 
87  item->copyprops( *this );
88 
89  item->saveonexit( saveonexit() );
90 
91  item->fire_resist( fire_resist() );
92  item->cold_resist( cold_resist() );
93  item->energy_resist( energy_resist() );
94  item->poison_resist( poison_resist() );
95  item->physical_resist( physical_resist() );
96 
97  item->fire_damage( fire_damage() );
98  item->cold_damage( cold_damage() );
99  item->energy_damage( energy_damage() );
100  item->poison_damage( poison_damage() );
101  item->physical_damage( physical_damage() );
102 
103  item->maxhp_mod( maxhp_mod() );
104  item->name_suffix( name_suffix() );
105 
106  item->no_drop( no_drop() );
107  return item;
108 }
109 
110 std::string Item::name() const
111 {
112  if ( !name_.get().empty() )
113  {
114  return name_;
115  }
116  else
117  {
118  const ItemDesc& id = this->itemdesc();
119 
120  if ( id.desc.get().empty() )
121  return Core::tile_desc( graphic );
122  else
123  return id.desc;
124  }
125 }
126 
127 const ItemDesc& Item::itemdesc() const
128 {
129  if ( _itemdesc == nullptr )
131  return *_itemdesc;
132 }
133 
150 std::string Item::description() const
151 {
152  std::string suffix = name_suffix();
153  if ( specific_name() )
154  {
155  return Core::format_description( 0, name(), amount_, suffix ); // dave monkeyed with this 2/4/3
156  }
157  else
158  {
159  const ItemDesc& id = this->itemdesc();
160  if ( id.desc.get().empty() )
161  {
163  amount_, suffix );
164  }
165  else
166  {
167  return Core::format_description( Core::tile_flags( graphic ), id.desc, amount_, suffix );
168  }
169  }
170 }
171 
172 std::string Item::get_use_script_name() const
173 {
174  return on_use_script_;
175 }
176 
177 std::string Item::merchant_description() const
178 {
179  std::string suffix = name_suffix();
180  if ( specific_name() )
181  {
182  return Core::format_description( 0, name(), 1, suffix );
183  }
184  else
185  {
186  const ItemDesc& id = this->itemdesc();
187  if ( id.desc.get().empty() )
188  {
189  return Core::format_description( 0, Core::tile_desc( graphic ), 1, suffix );
190  }
191  else
192  {
193  return Core::format_description( 0, id.desc, 1, suffix );
194  }
195  }
196 }
197 
199 {
200  u32 price = sellprice_();
201  if ( price == SELLPRICE_DEFAULT )
202  return itemdesc().vendor_sells_for;
203  return price;
204 }
205 void Item::sellprice( u32 value )
206 {
207  sellprice_( value );
208 }
209 
210 // Dave add buyprice() 11/28. Dont know wtf getbuyprice() is trying to do.
211 // Dave, getbuyprice() was trying to return false if the vendor wasn't interested in buying.
212 // it would return true if the vendor was interested in buying.
213 // -Eric
215 {
216  u32 price = buyprice_();
217  if ( price == BUYPRICE_DEFAULT )
218  return itemdesc().vendor_buys_for;
219  return price;
220 }
221 
222 void Item::buyprice( u32 value )
223 {
224  buyprice_( value );
225 }
226 
227 bool Item::getbuyprice( u32& bp ) const
228 {
229  bp = buyprice();
230  if ( bp > 0 )
231  return true;
232  else
233  return false;
234 }
235 
237 {
238  if ( container != nullptr )
239  return container->self_as_owner();
240  else
241  return nullptr;
242 }
243 
245 {
246  if ( container != nullptr )
247  return container->self_as_owner();
248  else
249  return nullptr;
250 }
251 
253 {
254  Item* item = this;
255  while ( item->container != nullptr )
256  item = item->container;
257 
258  return item;
259 }
260 
262 {
263  const Item* item = this;
264  while ( item->container != nullptr )
265  item = item->container;
266 
267  return item;
268 }
269 
270 const char* Item::classname() const
271 {
272  return "Item";
273 }
274 
276 {
278  return ( ( Core::tile_flags( graphic ) & Plib::FLAG::MOVABLE ) != 0 );
279  else
280  return itemdesc().movable ? true : false;
281 }
282 
284 {
285  return itemdesc().invisible;
286 }
287 
289 {
290  return itemdesc().newbie;
291 }
292 
294 {
295  return itemdesc().insured;
296 }
297 
300 {
301  if ( insured() )
302  {
303  set_dirty();
304  insured( false );
305  return true;
306  }
307  return false;
308 }
309 
310 bool Item::no_drop() const
311 {
313 }
314 
315 void Item::no_drop( bool newvalue )
316 {
318 }
319 
321 {
322  return itemdesc().no_drop;
323 }
324 
325 unsigned short Item::maxhp() const
326 {
327  int maxhp = itemdesc().maxhp + maxhp_mod();
328 
329  if ( maxhp < 1 )
330  return 1;
331  else if ( maxhp <= USHRT_MAX )
332  return static_cast<u16>( maxhp );
333  else
334  return USHRT_MAX;
335 }
336 
338 {
339  using namespace fmt;
340 
341  base::printProperties( sw );
342 
343  short maxhp_mod_ = maxhp_mod();
344  std::string suffix = name_suffix();
345 
346  if ( amount_ != 1 )
347  sw() << "\tAmount\t" << amount_ << pf_endl;
348 
349  if ( layer != 0 )
350  sw() << "\tLayer\t" << (int)layer << pf_endl;
351 
352  if ( movable() != default_movable() )
353  sw() << "\tMovable\t" << movable() << pf_endl;
354 
355  if ( invisible() != default_invisible() )
356  sw() << "\tInvisible\t" << invisible() << pf_endl;
357 
358  s16 value = fire_resist().mod;
359  if ( value != 0 )
360  sw() << "\tFireResistMod\t" << static_cast<int>( value ) << pf_endl;
361  value = cold_resist().mod;
362  if ( value != 0 )
363  sw() << "\tColdResistMod\t" << static_cast<int>( value ) << pf_endl;
364  value = energy_resist().mod;
365  if ( value != 0 )
366  sw() << "\tEnergyResistMod\t" << static_cast<int>( value ) << pf_endl;
367  value = poison_resist().mod;
368  if ( value != 0 )
369  sw() << "\tPoisonResistMod\t" << static_cast<int>( value ) << pf_endl;
370  value = physical_resist().mod;
371  if ( value != 0 )
372  sw() << "\tPhysicalResistMod\t" << static_cast<int>( value ) << pf_endl;
373 
374  value = fire_damage().mod;
375  if ( value != 0 )
376  sw() << "\tFireDamageMod\t" << static_cast<int>( value ) << pf_endl;
377  value = cold_damage().mod;
378  if ( value != 0 )
379  sw() << "\tColdDamageMod\t" << static_cast<int>( value ) << pf_endl;
380  value = energy_damage().mod;
381  if ( value != 0 )
382  sw() << "\tEnergyDamageMod\t" << static_cast<int>( value ) << pf_endl;
383  value = poison_damage().mod;
384  if ( value != 0 )
385  sw() << "\tPoisonDamageMod\t" << static_cast<int>( value ) << pf_endl;
386  value = physical_damage().mod;
387  if ( value != 0 )
388  sw() << "\tPhysicalDamageMod\t" << static_cast<int>( value ) << pf_endl;
389 
390  if ( container != nullptr )
391  sw() << "\tContainer\t0x" << hex( container->serial ) << pf_endl;
392 
393  if ( !on_use_script_.get().empty() )
394  sw() << "\tOnUseScript\t" << on_use_script_.get() << pf_endl;
395 
396  if ( equip_script_ != itemdesc().equip_script )
397  sw() << "\tEquipScript\t" << equip_script_.get() << pf_endl;
398 
399  if ( unequip_script_ != itemdesc().unequip_script )
400  sw() << "\tUnequipScript\t" << unequip_script_.get() << pf_endl;
401 
402  if ( decayat_gameclock_ != 0 )
403  sw() << "\tDecayAt\t" << decayat_gameclock_ << pf_endl;
404 
405  if ( has_sellprice_() )
406  sw() << "\tSellPrice\t" << sellprice_() << pf_endl;
407  if ( has_buyprice_() )
408  sw() << "\tBuyPrice\t" << buyprice_() << pf_endl;
409 
410  if ( newbie() != default_newbie() )
411  sw() << "\tNewbie\t" << newbie() << pf_endl;
412 
413  if ( insured() != default_insured() )
414  sw() << "\tInsured\t" << insured() << pf_endl;
415 
416  if ( maxhp_mod_ )
417  sw() << "\tMaxHp_mod\t" << maxhp_mod_ << pf_endl;
418  if ( hp_ != itemdesc().maxhp )
419  sw() << "\tHp\t" << hp_ << pf_endl;
420  double quali = getQuality();
421  if ( quali != getItemdescQuality() )
422  sw() << "\tQuality\t" << quali << pf_endl;
423  if ( !suffix.empty() )
424  sw() << "\tNameSuffix\t" << suffix << pf_endl;
425  if ( no_drop() != default_no_drop() )
426  sw() << "\tNoDrop\t" << no_drop() << pf_endl;
427 }
428 
430 {
432 }
433 
435 {
436  base::readProperties( elem );
437 
438  // Changed from Valid Color Mask to cfg mask in ssopt.
440 
441  amount_ = elem.remove_ushort( "AMOUNT", 1 );
442  layer = static_cast<unsigned char>( elem.remove_ushort( "LAYER", 0 ) );
443  movable( elem.remove_bool( "MOVABLE", default_movable() ) );
444  invisible( elem.remove_bool( "INVISIBLE", default_invisible() ) );
445 
446  // NOTE, container is handled specially - it is extracted by the creator.
447 
448  on_use_script_ = elem.remove_string( "ONUSESCRIPT", "" );
449  equip_script_ = elem.remove_string( "EQUIPSCRIPT", equip_script_.get().c_str() );
450  unequip_script_ = elem.remove_string( "UNEQUIPSCRIPT", unequip_script_.get().c_str() );
451 
452  decayat_gameclock_ = elem.remove_ulong( "DECAYAT", 0 );
453  sellprice_( elem.remove_ulong( "SELLPRICE", SELLPRICE_DEFAULT ) );
454  buyprice_( elem.remove_ulong( "BUYPRICE", BUYPRICE_DEFAULT ) );
455 
456  // buyprice used to be read in with remove_int (which was wrong).
457  // the UINT_MAX values used to be written out (which was wrong).
458  // when UINT_MAX is read in by atoi, it returned 2147483647 (0x7FFFFFFF)
459  // correct for this.
460  if ( buyprice_() == 2147483647 )
461  buyprice_( BUYPRICE_DEFAULT );
462  newbie( elem.remove_bool( "NEWBIE", default_newbie() ) );
463  insured( elem.remove_bool( "INSURED", default_insured() ) );
464  hp_ = elem.remove_ushort( "HP", itemdesc().maxhp );
465  setQuality( elem.remove_double( "QUALITY", itemdesc().quality ) );
466 
467  s16 mod_value = static_cast<s16>( elem.remove_int( "FIRERESISTMOD", 0 ) );
468  if ( mod_value != 0 )
469  fire_resist( fire_resist().setAsMod( mod_value ) );
470  mod_value = static_cast<s16>( elem.remove_int( "COLDRESISTMOD", 0 ) );
471  if ( mod_value != 0 )
472  cold_resist( cold_resist().setAsMod( mod_value ) );
473  mod_value = static_cast<s16>( elem.remove_int( "ENERGYRESISTMOD", 0 ) );
474  if ( mod_value != 0 )
475  energy_resist( energy_resist().setAsMod( mod_value ) );
476  mod_value = static_cast<s16>( elem.remove_int( "POISONRESISTMOD", 0 ) );
477  if ( mod_value != 0 )
478  poison_resist( poison_resist().setAsMod( mod_value ) );
479  mod_value = static_cast<s16>( elem.remove_int( "PHYSICALRESISTMOD", 0 ) );
480  if ( mod_value != 0 )
481  physical_resist( physical_resist().setAsMod( mod_value ) );
482 
483  mod_value = static_cast<s16>( elem.remove_int( "FIREDAMAGEMOD", 0 ) );
484  if ( mod_value != 0 )
485  fire_damage( fire_damage().setAsMod( mod_value ) );
486  mod_value = static_cast<s16>( elem.remove_int( "COLDDAMAGEMOD", 0 ) );
487  if ( mod_value != 0 )
488  cold_damage( cold_damage().setAsMod( mod_value ) );
489  mod_value = static_cast<s16>( elem.remove_int( "ENERGYDAMAGEMOD", 0 ) );
490  if ( mod_value != 0 )
491  energy_damage( energy_damage().setAsMod( mod_value ) );
492  mod_value = static_cast<s16>( elem.remove_int( "POISONDAMAGEMOD", 0 ) );
493  if ( mod_value != 0 )
494  poison_damage( poison_damage().setAsMod( mod_value ) );
495  mod_value = static_cast<s16>( elem.remove_int( "PHYSICALDAMAGEMOD", 0 ) );
496  if ( mod_value != 0 )
497  physical_damage( physical_damage().setAsMod( mod_value ) );
498 
499 
500  maxhp_mod( static_cast<s16>( elem.remove_int( "MAXHP_MOD", 0 ) ) );
501  name_suffix( elem.remove_string( "NAMESUFFIX", "" ) );
502  no_drop( elem.remove_bool( "NODROP", default_no_drop() ) );
503 }
504 
506 {
507  Core::send_sysmessage( client, "I can't think of a way to use that." );
508 }
509 
511 {
512  const ItemDesc& itemdesc = this->itemdesc();
513 
514  if ( itemdesc.requires_attention &&
515  ( client->chr->skill_ex_active() || client->chr->casting_spell() ) )
516  {
517  Core::send_sysmessage( client, "I am already doing something else." );
518  return;
519  }
520 
521  if ( itemdesc.requires_attention && client->chr->hidden() )
522  client->chr->unhide();
523 
525 
526  if ( !on_use_script_.get().empty() )
527  {
528  Core::ScriptDef sd( on_use_script_, nullptr, "" );
529  prog = find_script2( sd,
530  true, // complain if not found
531  Plib::systemstate.config.cache_interactive_scripts );
532  }
533  else if ( !itemdesc.on_use_script.empty() )
534  {
535  prog = find_script2( itemdesc.on_use_script, true,
537  }
538 
539  if ( prog.get() != nullptr )
540  {
541  if ( client->chr->start_itemuse_script( prog.get(), this, itemdesc.requires_attention ) )
542  return;
543  // else log the fact?
544  }
545  else
546  {
547  builtin_on_use( client );
548  }
549 }
550 
551 
552 unsigned short Item::get_senditem_amount() const
553 {
554  return amount_;
555 }
556 
557 bool Item::setlayer( unsigned char in_layer )
558 {
559  if ( Core::tilelayer( graphic ) == in_layer )
560  {
561  layer = in_layer;
562  return true;
563  }
564  else
565  {
566  return false;
567  }
568 }
569 
570 bool Item::stackable() const
571 {
572  return ( Core::tile_flags( graphic ) & Plib::FLAG::STACKABLE ) ? true : false;
573 }
574 
575 void Item::setamount( u16 amount )
576 {
577  set_dirty();
578  int oldweight = weight();
579 
580  if ( amount > amount_ ) // adding stuff
581  remove_resources( objtype_, amount - amount_ );
582  else
583  return_resources( objtype_, amount_ - amount );
584 
585  amount_ = amount;
586  int newweight = weight();
587  if ( container )
588  container->add_bulk( 0, newweight - oldweight );
589 
590  increv();
592 }
593 
594 void Item::subamount( u16 amount_subtract )
595 {
596  setamount( amount_ - amount_subtract );
597  increv();
598 }
599 
600 void Item::add_to_self( Item*& item )
601 {
602 #ifdef PERGON
603  ct_merge_stacks_pergon(
604  item ); // Pergon: Re-Calculate Property CreateTime after Merging of two Stacks
605 #endif
606 
607  setamount( amount_ + item->amount_ );
608 
609  if ( !item->newbie() )
610  newbie( false );
611 
612  if ( !item->insured() )
613  insured( false );
614 
615  item->destroy();
616  item = nullptr;
617 }
618 
619 #ifdef PERGON
620 // Pergon: Re-Calculate Property CreateTime after Merging of two Stacks
621 void Item::ct_merge_stacks_pergon( Item*& item_sub )
622 {
623  int time_self, time_sub, time;
624  std::string value_self, value_sub;
625 
626  // get "ct" of first stack - if error, init
627  if ( getprop( "ct", value_self ) )
628  {
629  Bscript::BObject imp( Bscript::BObjectImp::unpack( value_self.c_str() ) );
630  if ( imp.impptr() != nullptr && imp->isa( Bscript::BObjectImp::OTLong ) )
631  time_self = static_cast<Bscript::BLong*>( imp.impptr() )->value();
632  else
633  time_self = Core::read_gameclock();
634  }
635  else
636  time_self = Core::read_gameclock();
637 
638  // get "ct" of second stack - if error, init
639  if ( item_sub->getprop( "ct", value_sub ) )
640  {
641  Bscript::BObject imp( Bscript::BObjectImp::unpack( value_sub.c_str() ) );
642  if ( imp.impptr() != nullptr && imp->isa( Bscript::BObjectImp::OTLong ) )
643  time_sub = static_cast<Bscript::BLong*>( imp.impptr() )->value();
644  else
645  time_sub = Core::read_gameclock();
646  }
647  else
648  time_sub = Core::read_gameclock();
649 
650  // calculate new time
651  if ( time_self < time_sub )
652  {
653  double factor = ( item_sub->amount_ * 1.0 ) / ( amount_ + item_sub->amount_ );
654  time = int( ( time_sub - time_self ) * factor + time_self );
655  }
656  else if ( time_self > time_sub )
657  {
658  double factor = ( amount_ * 1.0 ) / ( amount_ + item_sub->amount_ );
659  time = int( ( time_self - time_sub ) * factor + time_sub );
660  }
661  else
662  time = time_self;
663 
664  setprop( "ct", "i" + Clib::decint( time ) );
665  increv();
666 }
667 
668 // Pergon: Re-Calculate Property CreateTime after Adding Items to a Stack
669 void Item::ct_merge_stacks_pergon( u16 amount_sub )
670 {
671  int time_self, time_sub, time;
672  std::string value_self;
673 
674  // get "ct" of first stack - if error, init
675  if ( getprop( "ct", value_self ) )
676  {
677  Bscript::BObject imp( Bscript::BObjectImp::unpack( value_self.c_str() ) );
678  if ( imp.impptr() != nullptr && imp->isa( Bscript::BObjectImp::OTLong ) )
679  time_self = static_cast<Bscript::BLong*>( imp.impptr() )->value();
680  else
681  time_self = Core::read_gameclock();
682  }
683  else
684  time_self = Core::read_gameclock();
685 
686  // set "ct" of second new stack
687  time_sub = Core::read_gameclock();
688 
689  // calculate new time
690  if ( time_self != time_sub )
691  {
692  double factor = ( amount_sub * 1.0 ) / ( amount_ + amount_sub );
693  time = int( ( time_sub - time_self ) * factor + time_self );
694  }
695  else
696  time = time_self;
697 
698  setprop( "ct", "i" + Clib::decint( time ) );
699  increv();
700 }
701 #endif
702 
703 bool Item::can_add_to_self( unsigned short amount, bool force_stacking ) const
704 {
705  if ( !force_stacking && !stackable() )
706  return false;
707 
708  unsigned int amount1 = (unsigned int)amount_;
709  unsigned int amount2 = (unsigned int)amount;
710 
711  if ( ( amount1 + amount2 ) > this->itemdesc().stack_limit )
712  return false;
713 
714  if ( container != nullptr )
715  {
716  int more_weight = weight_of( amount_ + amount ) - weight_of( amount_ );
717  if ( more_weight > USHRT_MAX /*std::numeric_limits<unsigned short>::max()*/ )
718  return false;
719  return container->can_add( static_cast<unsigned short>( more_weight ) );
720  }
721 
722  return true;
723 }
724 
725 bool Item::can_add_to_self( const Item& item, bool force_stacking )
726  const // dave 1/26/03 totally changed this function to handle the cprop comparisons.
727 {
728  bool res =
729  ( ( item.objtype_ == objtype_ ) && ( item.newbie() == newbie() ) &&
730  ( item.insured() == insured() ) && ( item.graphic == graphic ) && ( item.color == color ) &&
731  ( !inuse() ) && ( can_add_to_self( item.amount_, force_stacking ) ) );
732  if ( res == true )
733  {
734  // NOTE! this logic is copied in Item::has_only_default_cprops(), so make any necessary changes
735  // there too
736  Core::PropertyList myprops( getprops() ); // make a copy :(
737  myprops -= itemdesc().ignore_cprops;
739 
740  Core::PropertyList yourprops( item.getprops() ); // make a copy :(
741  yourprops -= item.itemdesc().ignore_cprops;
743 
744  res = ( myprops == yourprops );
745  }
746  return res;
747 }
748 
752 bool Item::has_only_default_cprops( const ItemDesc* compare ) const
753 {
754  if ( compare == nullptr )
755  compare = &( itemdesc() );
756  // logic same as Item::can_add_to_self()
757  Core::PropertyList myprops( getprops() ); // make a copy :(
758  myprops -= itemdesc().ignore_cprops;
760 
761  Core::PropertyList yourprops( compare->props ); // make a copy :(
762  yourprops -= compare->ignore_cprops;
764 
765  return ( myprops == yourprops );
766 }
767 
768 bool Item::amount_to_remove_is_partial( u16 this_item_new_amount ) const
769 {
770  return ( ( this_item_new_amount < amount_ ) && // less than what we have
771  ( amount_ > 1 ) && // we are a stack
772  ( this_item_new_amount > 0 ) ); // if new size 0, assume whole stack
773 }
774 
790 Item* Item::slice_stacked_item( u16 this_item_new_amount )
791 {
792  Item* new_item = clone();
793  if ( new_item != nullptr )
794  {
795  new_item->setamount( new_item->amount_ - this_item_new_amount );
796  setamount( this_item_new_amount );
797  }
798  return new_item;
799 }
800 
801 Item* Item::remove_part_of_stack( u16 amount_to_remove )
802 {
803  Item* new_item = clone();
804  if ( new_item != nullptr )
805  {
806  new_item->setamount( amount_to_remove );
807  subamount( amount_to_remove );
808  }
809  return new_item;
810 }
811 
812 
813 void Item::set_use_script( const std::string& scriptname )
814 {
815  set_dirty();
816  on_use_script_ = scriptname;
817 }
818 
819 bool Item::setgraphic( u16 newgraphic )
820 {
822  if ( layer && layer != Core::tilelayer( newgraphic ) )
823  {
824  return false;
825  }
826 
827  if ( graphic <= Plib::systemstate.config.max_tile_id &&
828  newgraphic <= Plib::systemstate.config.max_tile_id )
829  {
830  set_dirty();
831  graphic = newgraphic;
834 
836  const ItemDesc& id = this->itemdesc();
837 
838  if ( id.facing == 127 )
839  facing = tile_layer;
840  else
841  facing = id.facing;
842 
843  increv();
844  update_item_to_inrange( this );
845  return true;
846  }
847  else
848  {
849  return false;
850  }
851 }
852 
853 bool Item::setcolor( u16 newcolor )
854 {
856  bool res = true;
857  u16 theMask = (u16)Core::settingsManager.ssopt.item_color_mask;
858  if ( ( newcolor & ( ~theMask ) ) != 0 )
859  res = false;
860 
861  set_dirty();
862  newcolor &= ( theMask );
863 
864  if ( color != newcolor )
865  {
866  color = newcolor;
868  }
869 
870  return res;
871 }
872 
874 {
875  update_item_to_inrange( this );
876 }
877 
879 {
880  update_item_to_inrange( this );
881 }
882 
884 {
885  update_item_to_inrange( this );
886 }
887 
888 void Item::setfacing( u8 newfacing )
889 {
891  if ( newfacing > 127 )
892  newfacing = 0;
893 
894  if ( facing != newfacing )
895  {
896  facing = newfacing;
898  }
899 }
900 
902 {
903  update_item_to_inrange( this );
904 }
905 
907 {
908  if ( container != nullptr )
909  {
910  // hmm, a good place for a virtual?
912  {
914  passert_always( chr != nullptr ); // PRODFIXME linux-crash
915  passert_always( chr->is_equipped( this ) );
916 
917  chr->unequip( this ); // FIXME: should run unequip script
918  }
919  else
920  {
921  container->remove( this ); // FIXME: should probably call can/onRemove for the container
922  }
923  }
924 }
925 
926 void Item::spill_contents( Multi::UMulti* /*multi*/ ) {}
927 
928 unsigned int Item::weight_of( unsigned short amount ) const
929 {
930  const ItemDesc& id = this->itemdesc();
931  unsigned int amt = amount;
932  amt *= id.weightmult;
933  if ( id.weightdiv != 1 && id.weightdiv != 0 )
934  {
935  amt = ( amt + id.weightdiv - 1 ) / id.weightdiv;
936  }
937  return amt;
938 }
939 
940 unsigned int Item::weight() const
941 {
942  return weight_of( amount_ );
943 }
944 unsigned int Item::item_count() const
945 {
946  return 1;
947 }
948 
950 // Decay-related functions
952 
953 
954 void Item::set_decay_after( unsigned int seconds )
955 {
956  set_dirty();
957  // Why alter it, if it should not have it to begin with??
958  if ( decayat_gameclock_ != 0 )
959  {
961  }
962 }
963 
964 bool Item::can_decay() const
965 {
966  return !inuse() && ( movable() || ( objtype_ == UOBJ_CORPSE ) ) && decayat_gameclock_;
967 }
968 
969 bool Item::should_decay( unsigned int gameclock ) const
970 {
971  return can_decay() && ( gameclock > decayat_gameclock_ );
972 }
973 
975 {
976  // Why restart it, if it shouldn't have it to begin with??
977  if ( decayat_gameclock_ != 0 )
978  {
979  unsigned int dtime = itemdesc().decay_time * 60;
980  if ( should_decay( Core::read_gameclock() + dtime ) )
981  {
982  set_decay_after( dtime );
983  }
984  }
985 }
986 
988 {
989  set_dirty();
990  decayat_gameclock_ = 0;
991 }
992 
994 // Equip-Script related functions
997 {
998  return !equip_script_.get().empty();
999 }
1000 
1002 {
1003  Core::ScriptDef sd;
1004 
1005  try
1006  {
1007  sd.config( equip_script_, itemdesc().pkg, "scripts/control/" );
1008  }
1009  catch ( std::exception& ex )
1010  {
1011  return new Bscript::BError( std::string( "Script descriptor error" ) + ex.what() );
1012  }
1013 
1014  try
1015  {
1017  new Module::EItemRefObjImp( this ),
1018  new Bscript::BLong( startup ? 1 : 0 ) );
1019  }
1020  catch ( std::exception& ex )
1021  {
1022  return new Bscript::BError( std::string( "Script execution error" ) + ex.what() );
1023  }
1024 }
1025 
1027 {
1028  Core::ScriptDef sd;
1029 
1030  try
1031  {
1032  sd.config( unequip_script_, itemdesc().pkg, "scripts/control/" );
1033  }
1034  catch ( std::exception& ex )
1035  {
1036  return new Bscript::BError( std::string( "Script descriptor error: " ) + ex.what() );
1037  }
1038 
1039  try
1040  {
1042  new Module::EItemRefObjImp( this ) );
1043  }
1044  catch ( std::exception& ex )
1045  {
1046  return new Bscript::BError( std::string( "Script execution error:" ) + ex.what() );
1047  }
1048 }
1049 
1050 
1052 {
1053  if ( has_equip_script() )
1054  {
1055  Bscript::BObject obj( run_equip_script( chr, startup ) );
1056  return obj.isTrue();
1057  }
1058  else
1059  {
1060  return true;
1061  }
1062 }
1063 
1065 {
1066  if ( !unequip_script_.get().empty() && container != nullptr &&
1068  {
1070  passert_always( chr != nullptr );
1071  passert_always( chr->is_equipped( this ) );
1072 
1073  Bscript::BObject obj( run_unequip_script( chr ) );
1074  return obj.isTrue();
1075  }
1076  else
1077  {
1078  return true;
1079  }
1080 }
1081 
1082 void preload_test_scripts( const std::string& script_ecl )
1083 {
1084  Core::ScriptDef sd;
1085  sd.quickconfig( "scripts/misc/" + script_ecl );
1086  if ( sd.exists() )
1087  {
1088  find_script2( sd, true, true );
1089  }
1090  for ( const auto& pkg : Plib::systemstate.packages )
1091  {
1092  sd.quickconfig( pkg, script_ecl );
1093  if ( sd.exists() )
1094  {
1095  find_script2( sd, true, true );
1096  }
1097  }
1098 }
1100 {
1101  preload_test_scripts( "equiptest.ecl" );
1102  preload_test_scripts( "unequiptest.ecl" );
1103 }
1104 
1105 bool Item::check_test_scripts( Mobile::Character* chr, const std::string& script_ecl, bool startup )
1106 {
1107  Core::ScriptDef sd;
1108  sd.quickconfig( "scripts/misc/" + script_ecl );
1109  this->inuse( true );
1110  if ( script_loaded( sd ) )
1111  {
1112  bool res =
1114  new Module::EItemRefObjImp( this ), new Bscript::BLong( startup ) );
1115  this->inuse( false );
1116  if ( !res )
1117  return false;
1118  }
1119  for ( const auto& pkg : Plib::systemstate.packages )
1120  {
1121  sd.quickconfig( pkg, script_ecl );
1122  if ( script_loaded( sd ) )
1123  {
1124  bool res =
1126  new Module::EItemRefObjImp( this ), new Bscript::BLong( startup ) );
1127  this->inuse( false );
1128  if ( !res )
1129  return false;
1130  }
1131  }
1132 
1133  this->inuse( false );
1134  return true;
1135 }
1136 
1138 {
1139  return check_test_scripts( chr, "equiptest.ecl", startup );
1140 }
1141 
1143 {
1144  return check_test_scripts( chr, "unequiptest.ecl", false );
1145 }
1146 
1148 {
1149  if ( container != nullptr && Core::IsCharacter( container->serial ) )
1150  {
1152  passert_always( chr != nullptr );
1153  passert_always( chr->is_equipped( this ) );
1154 
1155  return check_unequiptest_scripts( chr );
1156  }
1157  else
1158  {
1159  return true;
1160  }
1161 }
1162 
1169 {
1170  UObject* top_level_item = toplevel_owner();
1171  if ( top_level_item->isa( Core::UOBJ_CLASS::CLASS_CONTAINER ) )
1172  {
1173  Mobile::Character* chr_owner =
1174  Core::chr_from_wornitems( static_cast<Core::UContainer*>( top_level_item ) );
1175  if ( chr_owner != nullptr )
1176  {
1177  return chr_owner;
1178  }
1179  else
1180  return nullptr;
1181  }
1182  else
1183  return nullptr;
1184 }
1185 
1186 const char* Item::target_tag() const
1187 {
1188  return "item";
1189 }
1190 
1192 {
1193  return itemdesc().quality;
1194 }
1195 
1196 double Item::getQuality() const
1197 {
1198  return quality();
1199 }
1200 void Item::setQuality( double value )
1201 {
1202  quality( value );
1203 }
1204 }
1205 }
bool empty() const
Definition: scrdef.h:41
unsigned char u8
Definition: rawtypes.h:25
bool newbie() const
Definition: item.h:338
bool script_loaded(ScriptDef &sd)
Definition: scrstore.cpp:32
std::string format_description(unsigned int polflags, const std::string &descdef, unsigned short amount, const std::string suffix)
Definition: ufunc.cpp:1786
virtual void on_facing_changed() POL_OVERRIDE
Definition: item.cpp:901
static Item * create(u32 objtype, u32 serial=0)
Definition: itemcr.cpp:53
unsigned int tile_flags(unsigned short tilenum)
Definition: polfile2.cpp:49
virtual std::string description() const POL_OVERRIDE
Definition: item.cpp:150
unsigned short stack_limit
Definition: itemdesc.h:126
Core::PropertyList props
Definition: itemdesc.h:138
bool check_unequiptest_scripts()
Definition: item.cpp:1147
void subamount(u16 amount_subtract)
Definition: item.cpp:594
PropSet Global_Ignore_CProps
Definition: uvars.h:232
virtual bool setcolor(u16 newcolor) POL_OVERRIDE
Definition: item.cpp:853
ref_ptr< Bscript::EScriptProgram > find_script2(const ScriptDef &script, bool complain_if_not_found, bool cache_script)
Definition: scrstore.cpp:83
void quickconfig(const Plib::Package *pkg, const std::string &name_ecl)
Definition: scrdef.cpp:112
bool should_decay(unsigned int gameclock) const
Definition: item.cpp:969
bool can_add_to_self(unsigned short amount, bool force_stacking) const
Definition: item.cpp:703
Character * chr_from_wornitems(UContainer *wornitems)
Definition: ufunc.cpp:1529
unsigned decay_time
Definition: itemdesc.h:107
std::string remove_string(const char *propname)
Definition: cfgfile.cpp:381
virtual UObject * owner() POL_OVERRIDE
Definition: item.cpp:236
virtual bool can_add(const Items::Item &item) const
Definition: containr.cpp:168
bool stackable() const
Definition: item.cpp:570
void return_resources(u32 objtype, u16)
Definition: itemdesc.cpp:1232
bool skill_ex_active() const
Definition: charactr.h:1013
bool check_unequip_script()
Definition: item.cpp:1064
SystemState systemstate
Definition: systemstate.cpp:12
bool isa(BObjectType type) const
Definition: bobject.h:353
void setprop(const std::string &propname, const std::string &propvalue)
Definition: uobject.cpp:160
virtual void add_bulk(int item_count_delta, int weight_delta)
Definition: containr.cpp:215
Core::PolConfig config
Definition: systemstate.h:43
virtual UObject * toplevel_owner() POL_OVERRIDE
Definition: item.cpp:252
static const u32 SELLPRICE_DEFAULT
Definition: item.h:291
unsigned char tilelayer(unsigned short tilenum)
Definition: polfile2.cpp:22
bool getbuyprice(u32 &buyprice) const
Definition: item.cpp:227
virtual std::string name() const POL_OVERRIDE
Definition: item.cpp:110
bool specific_name() const
Definition: uobject.h:286
std::set< std::string > ignore_cprops
Definition: itemdesc.h:139
T * get() const
Definition: refptr.h:176
std::string decint(unsigned short v)
Definition: strutil.cpp:64
void preload_test_scripts(const std::string &script_ecl)
Definition: item.cpp:1082
unsigned int remove_ulong(const char *propname)
Definition: cfgfile.cpp:461
std::string merchant_description() const
Definition: item.cpp:177
virtual void printProperties(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: item.cpp:337
boost_utils::script_name_flystring on_use_script_
Definition: item.h:263
bool get(ENUM flag) const
Definition: uobject.h:108
int remove_int(const char *propname)
Definition: cfgfile.cpp:340
bool has_equip_script() const
Definition: item.cpp:996
unsigned int vendor_sells_for
Definition: itemdesc.h:105
void disable_decay()
Definition: item.cpp:987
bool casting_spell() const
Definition: charactr.h:1018
bool use_insurance()
Returns current insurance value and resets it to false.
Definition: item.cpp:299
virtual void on_color_changed() POL_OVERRIDE
Definition: item.cpp:873
boost_utils::script_name_flystring unequip_script_
Definition: item.h:265
virtual void setQuality(double value)
Definition: item.cpp:1200
virtual Item * clone() const
Definition: item.cpp:56
static const u32 BUYPRICE_DEFAULT
Definition: item.h:292
const ItemDesc & find_itemdesc(unsigned int objtype)
Definition: itemdesc.cpp:933
unsigned int max_tile_id
Definition: polcfg.h:61
void add_to_self(Item *&item)
Definition: item.cpp:600
virtual void builtin_on_use(Network::Client *client)
Definition: item.cpp:505
std::string tile_desc(unsigned short tilenum)
Definition: polfile2.cpp:73
Mobile::Character * chr
Definition: client.h:182
virtual Items::Item * remove(u32 serial, UContainer **found_in=nullptr)
Definition: containr.cpp:510
virtual u16 get_senditem_amount() const
Definition: item.cpp:552
static gameclock_t gameclock
Definition: gameclck.cpp:21
unsigned short maxhp() const
Definition: item.cpp:325
virtual const char * classname() const POL_OVERRIDE
Definition: item.cpp:270
Core::ScriptDef on_use_script
Definition: itemdesc.h:97
double remove_double(const char *propname, double dflt)
Definition: cfgfile.cpp:448
void set_dirty()
Definition: uobject.h:291
bool no_drop() const
Definition: item.cpp:310
virtual void readProperties(Clib::ConfigElem &elem) POL_OVERRIDE
Definition: item.cpp:434
unsigned short u16
Definition: rawtypes.h:26
unsigned int u32
Definition: rawtypes.h:27
bool setlayer(unsigned char layer)
Definition: item.cpp:557
bool getprop(const std::string &propname, std::string &propvalue) const
Definition: uobject.cpp:155
unsigned short maxhp
Definition: itemdesc.h:129
void setamount(u16 amount)
Definition: item.cpp:575
bool exists() const
Definition: scrdef.cpp:126
bool call_script(const ScriptDef &script, Bscript::BObjectImp *param0)
Definition: scrsched.cpp:546
bool start_itemuse_script(Bscript::EScriptProgram *prog, Items::Item *item, bool start_attached)
Definition: chrituse.cpp:82
bool check_test_scripts(Mobile::Character *chr, const std::string &script_ecl, bool startup)
Definition: item.cpp:1105
virtual void destroy()
Definition: uobject.cpp:122
signed short s16
Definition: rawtypes.h:30
AttributeFlags< OBJ_FLAGS > flags_
Definition: uobject.h:274
void unequip(Items::Item *item)
Definition: charactr.cpp:1464
void config(const std::string &name, const Plib::Package *pkg, const char *mainpfx, bool warn_if_not_found=true)
Definition: scrdef.cpp:55
virtual UObject * self_as_owner()
Definition: uobject.cpp:224
void set_use_script(const std::string &scriptname)
Definition: item.cpp:813
bool check_equip_script(Mobile::Character *chr, bool startup)
Definition: item.cpp:1051
void set_decay_after(unsigned int seconds)
Definition: item.cpp:954
#define UOBJ_CORPSE
Definition: objtype.h:218
virtual void spill_contents(Multi::UMulti *supporting_multi)
Definition: item.cpp:926
virtual void double_click(Network::Client *client)
Definition: item.cpp:510
char tileheight(unsigned short tilenum)
Definition: polfile2.cpp:34
virtual void setfacing(u8 newfacing) POL_OVERRIDE
Definition: item.cpp:888
bool has_only_default_cprops(const ItemDesc *compare=nullptr) const
Definition: item.cpp:752
void on_movable_changed()
Definition: item.cpp:878
const PropertyList & getprops() const
Definition: uobject.cpp:191
u32 sellprice() const
Definition: item.cpp:198
static BObjectImp * unpack(const char *pstr)
Definition: object.cpp:120
unsigned int decayat_gameclock_
Definition: item.h:259
virtual const char * target_tag() const POL_OVERRIDE
Definition: item.cpp:1186
virtual unsigned int item_count() const
Definition: item.cpp:944
Core::UContainer * container
Definition: item.h:256
gameclock_t read_gameclock()
Reads the current value of the game clock.
Definition: gameclck.cpp:57
const u32 objtype_
Definition: uobject.h:249
GameState gamestate
Definition: uvars.cpp:74
Item * remove_part_of_stack(u16 amount_to_remove)
Definition: item.cpp:801
BObjectImp * impptr()
Definition: bobject.h:428
void remove_resources(u32 objtype, u16)
Definition: itemdesc.cpp:1223
bool cache_interactive_scripts
Definition: polcfg.h:51
SettingsManager settingsManager
Definition: settings.cpp:14
bool movable() const
Definition: item.h:300
bool saveonexit() const
Definition: uobject.cpp:385
u32 buyprice() const
Definition: item.cpp:214
bool default_no_drop() const
Definition: item.cpp:320
bool IsCharacter(u32 serial)
Definition: uobject.h:311
bool default_insured() const
Definition: item.cpp:293
virtual void printDebugProperties(Clib::StreamWriter &sw) const
Definition: uobject.cpp:275
bool invisible() const
Definition: item.h:324
void restart_decay_timer()
Definition: item.cpp:974
bool is_equipped(const Items::Item *item) const
Definition: charactr.cpp:1342
virtual void readProperties(Clib::ConfigElem &elem)
Definition: uobject.cpp:287
bool default_invisible() const
Definition: item.cpp:283
Realms::Realm * realm
Definition: baseobject.h:56
std::string get_use_script_name() const
Definition: item.cpp:172
bool default_movable() const
Definition: item.cpp:275
bool isTrue() const
Definition: bobject.h:384
unsigned short remove_ushort(const char *propname)
Definition: cfgfile.cpp:318
virtual double getQuality() const
Definition: item.cpp:1196
bool run_script_to_completion(const char *filename, Bscript::BObjectImp *parameter)
Definition: scrsched.cpp:333
bool default_newbie() const
Definition: item.cpp:288
unsigned short hp_
Definition: item.h:271
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
void change(ENUM flag, bool value)
Definition: uobject.h:115
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 bool setgraphic(u16 newobjtype) POL_OVERRIDE
Definition: item.cpp:819
void on_invisible_changed()
Definition: item.cpp:883
Item * slice_stacked_item(u16 this_item_new_amount)
Definition: item.cpp:790
virtual void printDebugProperties(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: item.cpp:429
bool inuse() const
Definition: item.h:314
virtual void printProperties(Clib::StreamWriter &sw) const
Definition: uobject.cpp:245
Bscript::BObjectImp * run_equip_script(Mobile::Character *chr, bool startup)
Definition: item.cpp:1001
const ItemDesc & itemdesc() const
Definition: item.cpp:127
double getItemdescQuality() const
Definition: item.cpp:1191
unsigned short item_color_mask
Definition: ssopt.h:59
unsigned int vendor_buys_for
Definition: itemdesc.h:106
virtual unsigned int weight() const POL_OVERRIDE
Definition: item.cpp:940
#define passert_always(exp)
Definition: passert.h:80
void send_object_cache_to_inrange(const UObject *obj)
Definition: tooltips.cpp:77
enum Pol::Items::ItemDesc::Movable movable
void extricate()
Definition: item.cpp:906
#define pf_endl
Definition: proplist.cpp:25
Mobile::Character * GetCharacterOwner()
Definition: item.cpp:1168
const ItemDesc * _itemdesc
Definition: item.h:266
bool insured() const
Definition: item.h:348
Definition: berror.cpp:12
boost_utils::object_name_flystring name_
Definition: uobject.h:272
Bscript::BObjectImp * run_unequip_script(Mobile::Character *who)
Definition: item.cpp:1026
bool remove_bool(const char *propname)
Definition: cfgfile.cpp:426
void copyprops(const UObject &obj)
Definition: uobject.cpp:174
void send_sysmessage(Network::Client *client, const char *text, unsigned short font, unsigned short color)
Definition: ufunc.cpp:1147
unsigned int weight_of(unsigned short amount) const
Definition: item.cpp:928
bool can_decay() const
Definition: item.cpp:964
bool hidden() const
Definition: charactr.h:941
void update_item_to_inrange(const Item *item)
Definition: ufunc.cpp:737
boost_utils::script_name_flystring equip_script_
Definition: item.h:264