Pol  Revision:cb584c9
charactr.cpp
Go to the documentation of this file.
1 
82 #include "pol_global_config.h"
83 
84 #include "charactr.h"
85 
86 #include <stdlib.h>
87 #include <string>
88 
89 #include "../../clib/cfgelem.h"
90 #include "../../clib/cfgfile.h"
91 #include "../../clib/clib.h"
92 #include "../../clib/clib_endian.h"
93 #include "../../clib/esignal.h"
94 #include "../../clib/fileutil.h"
95 #include "../../clib/logfacility.h"
96 #include "../../clib/passert.h"
97 #include "../../clib/random.h"
98 #include "../../clib/stlutil.h"
99 #include "../../clib/streamsaver.h"
100 #include "../../plib/mapcell.h"
101 #include "../../plib/systemstate.h"
102 #include "../accounts/account.h"
103 #include "../accounts/accounts.h"
104 #include "../checkpnt.h"
105 #include "../clidata.h"
106 #include "../cmbtcfg.h"
107 #include "../cmdlevel.h"
108 #include "../containr.h"
109 #include "../dice.h"
110 #include "../extobj.h"
111 #include "../fnsearch.h"
112 #include "../globals/settings.h"
113 #include "../globals/state.h"
114 #include "../globals/uvars.h"
115 #include "../guardrgn.h"
116 #include "../guilds.h"
117 #include "../item/armor.h"
118 #include "../item/item.h"
119 #include "../item/itemdesc.h"
120 #include "../item/weapon.h"
121 #include "../item/wepntmpl.h"
122 #include "../layers.h"
123 #include "../mdelta.h"
124 #include "../miscrgn.h"
125 #include "../mkscrobj.h"
126 #include "../module/osmod.h"
127 #include "../module/uomod.h"
128 #include "../movecost.h"
129 #include "../multi/customhouses.h"
130 #include "../multi/house.h"
131 #include "../multi/multi.h"
132 #include "../multi/multidef.h"
133 #include "../musicrgn.h"
134 #include "../network/cgdata.h"
135 #include "../network/client.h"
136 #include "../network/cliface.h"
137 #include "../network/packetdefs.h"
138 #include "../network/packethelper.h"
139 #include "../network/packets.h"
140 #include "../objtype.h"
141 #include "../party.h"
142 #include "../pktdef.h"
143 #include "../polclass.h"
144 #include "../polsig.h"
145 #include "../polvar.h"
146 #include "../profile.h"
147 #include "../realms/WorldChangeReasons.h"
148 #include "../realms/realm.h"
149 #include "../schedule.h"
150 #include "../scrdef.h"
151 #include "../scrsched.h"
152 #include "../scrstore.h"
153 #include "../sfx.h"
154 #include "../skilladv.h"
155 #include "../spelbook.h"
156 #include "../statmsg.h"
157 #include "../syshook.h"
158 #include "../ufunc.h"
159 #include "../ufuncstd.h"
160 #include "../uobjcnt.h"
161 #include "../uoexec.h"
162 #include "../uoscrobj.h"
163 #include "../uworld.h"
164 #include "../vital.h"
165 #include "attribute.h"
166 #include "corpse.h"
167 #include "privupdater.h"
168 #include "wornitems.h"
169 
170 #ifdef _MSC_VER
171 #pragma warning( disable : 4505 ) // unreferenced local function has been removed
172 #endif
173 
174 namespace Pol
175 {
176 namespace Core
177 {
178 void cancel_trade( Mobile::Character* chr1 );
179 }
180 namespace Mobile
181 {
182 unsigned short layer_to_zone( unsigned short layer )
183 {
184  for ( unsigned short zone = 0; zone < Core::gamestate.armorzones.size(); ++zone )
185  {
186  for ( unsigned i = 0; i < Core::gamestate.armorzones[zone].layers.size(); ++i )
187  {
188  if ( Core::gamestate.armorzones[zone].layers[i] == layer )
189  return zone;
190  }
191  }
192  ERROR_PRINT << "Couldn't find an Armor Zone in armrzone.cfg for layer " << layer << "\n";
193  throw std::runtime_error( "Configuration file error" );
194 }
195 
196 const char* zone_to_zone_name( unsigned short zone )
197 {
198  return Core::gamestate.armorzones[zone].name.c_str();
199 }
200 
201 unsigned short zone_name_to_zone( const char* zname )
202 {
203  for ( unsigned short zone = 0; zone < Core::gamestate.armorzones.size(); ++zone )
204  {
205  if ( stricmp( Core::gamestate.armorzones[zone].name.c_str(), zname ) == 0 )
206  {
207  return zone;
208  }
209  }
210  ERROR_PRINT << "Couldn't find an armrzone.cfg config elem named '" << zname << "'\n";
211 
212  throw std::runtime_error( "Configuration file error" );
213 }
215 {
216  if ( !Clib::FileExists( "config/armrzone.cfg" ) )
217  {
218  if ( Plib::systemstate.config.loglevel > 1 )
219  INFO_PRINT << "File config/armrzone.cfg not found, skipping.\n";
220  return;
221  }
222  Clib::ConfigFile cf( "config/armrzone.cfg" );
223  Clib::ConfigElem elem;
224 
226  Core::gamestate.armorzones.clear();
227 
228  while ( cf.read( elem ) )
229  {
230  // armorzones.push_back( ArmorZone( elem ) );
231  Core::ArmorZone az;
232  az.name = elem.remove_string( "NAME" );
233  az.chance = static_cast<double>( elem.remove_ushort( "CHANCE" ) ) / 100.0;
234  unsigned short in_layer;
235  while ( elem.remove_prop( "LAYER", &in_layer ) )
236  {
237  if ( in_layer < Core::LOWEST_LAYER || in_layer > Core::HIGHEST_LAYER )
238  {
239  ERROR_PRINT << "ArmorZone " << az.name << ": Layer " << in_layer << " is out of range.\n"
240  << "Valid range is " << Core::LOWEST_LAYER << " to " << Core::HIGHEST_LAYER
241  << "\n";
242  throw std::runtime_error( "Configuration file error" );
243  }
244  az.layers.push_back( in_layer );
245  }
246 
247  Core::gamestate.armorzones.push_back( az );
249  }
250 }
251 
253 {
254  Core::gamestate.armorzones.clear();
256 }
257 
258 
260  : UObject( objtype, uobj_class ),
261  // NPC
262  // EQUIPMENT / ITEMS
263  weapon( Core::gamestate.wrestling_weapon ),
264  shield( nullptr ),
265  armor_( Core::gamestate.armorzones.size() ),
266  wornitems( new Core::WornItemsContainer ), // default objtype is in containr.cpp,
267  // WornItemsContainer class
268  gotten_item_source( GOTTEN_ITEM_ON_GROUND ),
269  remote_containers_(),
270  // MOVEMENT
271  dir( 0 ),
272  gradual_boost( 0 ),
273  lastx( 0 ),
274  lasty( 0 ),
275  lastz( 0 ),
276  move_reason( OTHER ),
277  movemode( Core::MOVEMODE_LAND ),
278  // COMBAT
279  warmode_wait( 0 ),
280  ar_( 0 ),
281  opponent_( nullptr ),
282  opponent_of(),
283  swing_timer_start_clock_( 0 ),
284  swing_task( nullptr ),
285  // ATTRIBUTES / VITALS
286  disable_regeneration_until( 0 ),
287  attributes( Core::gamestate.numAttributes ),
288  vitals( Core::gamestate.numVitals ),
289  // REPUTATION
290  aggressor_to_(),
291  lawfully_damaged_(),
292  criminal_until_( 0 ),
293  repsys_task_( nullptr ),
294  to_be_reportable_(),
295  reportable_(),
296  // GUILD
297  // PARTY
298  party_decline_timeout_( nullptr ),
299  // SECURE TRADING
300  trading_cont(),
301  trading_with( nullptr ),
302  // SCRIPT
303  tcursor2( nullptr ),
304  menu( nullptr ),
305  on_menu_selection( nullptr ),
306  on_popup_menu_selection( nullptr ),
307  script_ex( nullptr ),
308  spell_task( nullptr ),
309  // CLIENT
310  client( nullptr ),
311  uclang( "enu" ),
312  _last_textcolor( 0 ),
313  // PRIVS SETTINGS STATUS
314  cmdlevel_( 0 ),
315  concealed_( 0 ),
316  stealthsteps_( 0 ),
317  mountedsteps_( 0 ),
318  privs(),
319  settings(),
320  cached_settings(),
321  mob_flags_(),
322  // SERIALIZATION
323  // CREATION
324  created_at( 0 ),
325  // BUFFS
326  buffs_(),
327  // MISC
328  acct( nullptr ),
329  registered_house( 0 ),
330  truecolor( 0 ),
331  trueobjtype( 0 ),
332  // Note, Item uses the named constructor idiom, but here, it is not used.
333  // this is probably okay, but something to keep in mind.
334  gender( Core::GENDER_MALE ),
335  race( Core::RACE_HUMAN ),
336  last_corpse( 0 )
337 {
338  logged_in( true ); // so initialization scripts etc can see
339 
341  .default_character_height; // this gets overwritten in UObject::readProperties!
342  wornitems->chr_owner = this; // FIXME, dangerous.
343 
345 
346  // vector
347  refresh_cached_settings( false );
349 }
350 
352 {
353  if ( acct.get() )
354  {
355  for ( int i = 0; i < Plib::systemstate.config.character_slots; i++ )
356  {
357  if ( acct->get_character( i ) == this )
358  {
359  acct->clear_character( i );
360  }
361  }
362  }
363  acct.clear();
364 
365  if ( client && ( client->chr == this ) )
366  client->chr = nullptr;
367  client = nullptr;
368 
369  // It might be nice to do this only when the system isn't shutting down...
370  // if (!opponent_of.empty())
371  //{
372  // Clib::Log( "Destroying character with nonempty opponent_of! (But cleaning up..)\n" );
373  //}
374 
375  removal_cleanup();
376 
377  // clean up wornitems, so it can be reaped by the objecthash later
378  wornitems->destroy();
379 
380  // clean up trade container if it exists
381  if ( trading_cont != nullptr )
382  trading_cont->destroy();
383 
384  if ( repsys_task_ != nullptr )
385  repsys_task_->cancel();
386 
387  if ( party_decline_timeout_ != nullptr )
389 
391 }
392 
394 {
396 
397  /* This used to be a call to set_opponent(nullptr),
398  which was slick,
399  but that was sending disengage events, which were
400  trying to resurrect this object. (C++)
401  */
402  if ( opponent_ != nullptr )
403  {
404  opponent_->opponent_of.erase( this );
405  // This is cleanup, wtf we doing trying to send highlights?!
406  // opponent_->send_highlight();
407  // opponent_->schedule_attack();
408  opponent_ = nullptr;
409  }
410 
411  if ( swing_task != nullptr )
412  swing_task->cancel();
413 
415 }
416 
418 {
419  if ( is_trading() )
420  Core::cancel_trade( this );
421 
422  tcursor2 = nullptr;
423 
425  on_loggoff_party( this );
426 }
427 
429 {
431 }
432 
433 void Character::logged_in( bool newvalue )
434 {
436 }
437 
439 {
441 }
442 
443 void Character::connected( bool newvalue )
444 {
446 }
447 
449 {
450  return ( client != nullptr && client->isActive() );
451 }
452 
454 {
455  return ( client != nullptr && client->gd != nullptr &&
457 }
458 
460 {
461  return ( client != nullptr && client->gd != nullptr && !client->gd->gumpmods.empty() );
462 }
463 
465 {
466  return ( client != nullptr && client->gd != nullptr && client->gd->custom_house_serial != 0 );
467 }
468 
470 {
471  auto item = gotten_item();
472  if ( item != nullptr )
473  {
474  gotten_item( nullptr );
475  item->inuse( false );
476  if ( connected() )
478  undo_get_item( this, item );
479  }
480 }
481 
483 {
485  if ( registered_house > 0 )
486  {
488  if ( multi != nullptr )
489  {
490  multi->unregister_object( (UObject*)this );
491  }
492  registered_house = 0;
493  }
494  base::destroy();
495 }
496 
498 {
499  if ( script_ex != nullptr )
500  {
501  // this will force the execution engine to stop running this script immediately
502  // dont delete the executor here, since it could currently run
503  script_ex->seterror( true );
507  }
508 }
509 
513 unsigned int Character::weight() const
514 {
515  unsigned int wt = 10 + wornitems->weight();
516  if ( has_gotten_item() )
517  wt += gotten_item()->weight();
518  if ( trading_cont.get() )
519  wt += trading_cont->weight();
520  return wt;
521 }
522 
527 unsigned short Character::carrying_capacity() const
528 {
529  return static_cast<u16>( floor( ( 40 + strength() * 7 / 2 + carrying_capacity_mod() ) *
530  Core::settingsManager.ssopt.carrying_capacity_mod ) );
531 }
532 
534 {
535  if ( acct == nullptr )
536  return -1;
537 
538  for ( int i = 0; i < Plib::systemstate.config.character_slots; i++ )
539  {
540  if ( acct->get_character( i ) == this )
541  return i;
542  }
543 
544  POLLOG_INFO << "Warning: Can't find charidx for Character 0x" << fmt::hexu( serial ) << "\n";
545  return -1;
546 }
547 
548 
550 {
551  using namespace fmt;
552 
553  if ( acct != nullptr )
554  {
555  sw() << "\tAccount\t" << acct->name() << pf_endl;
556  sw() << "\tCharIdx\t" << charindex() << pf_endl;
557  }
558 
559  base::printProperties( sw );
560 
561  if ( cmdlevel_ )
562  {
563  sw() << "\tCmdLevel\t" << Core::gamestate.cmdlevels[cmdlevel_].name << pf_endl;
564  }
565  if ( concealed_ )
566  {
567  sw() << "\tConcealed\t" << int( concealed_ ) << pf_endl;
568  }
569  sw() << "\tTrueColor\t0x" << hex( truecolor ) << pf_endl;
570  sw() << "\tTrueObjtype\t0x" << hex( trueobjtype ) << pf_endl;
571 
572  if ( registered_house )
573  sw() << "\tRegisteredHouse\t0x" << hex( registered_house ) << pf_endl;
574 
575  sw() << "\tGender\t" << static_cast<int>( gender ) << pf_endl;
576  sw() << "\tRace\t" << static_cast<int>( race ) << pf_endl;
577 
578  if ( dead() )
579  sw() << "\tDead\t" << static_cast<int>( dead() ) << pf_endl;
580 
581  if ( mountedsteps_ )
582  sw() << "\tMountedSteps\t" << static_cast<unsigned int>( mountedsteps_ ) << pf_endl;
583 
584  if ( hidden() )
585  sw() << "\tHidden\t" << static_cast<int>( hidden() ) << pf_endl;
586 
587  if ( frozen() )
588  sw() << "\tFrozen\t" << static_cast<int>( frozen() ) << pf_endl;
589 
590  s16 value = fire_resist().mod;
591  if ( value != 0 )
592  sw() << "\tFireResistMod\t" << static_cast<int>( value ) << pf_endl;
593  value = cold_resist().mod;
594  if ( value != 0 )
595  sw() << "\tColdResistMod\t" << static_cast<int>( value ) << pf_endl;
596  value = energy_resist().mod;
597  if ( value != 0 )
598  sw() << "\tEnergyResistMod\t" << static_cast<int>( value ) << pf_endl;
599  value = poison_resist().mod;
600  if ( value != 0 )
601  sw() << "\tPoisonResistMod\t" << static_cast<int>( value ) << pf_endl;
602  value = physical_resist().mod;
603  if ( value != 0 )
604  sw() << "\tPhysicalResistMod\t" << static_cast<int>( value ) << pf_endl;
605 
606  value = fire_damage().mod;
607  if ( value != 0 )
608  sw() << "\tFireDamageMod\t" << static_cast<int>( value ) << pf_endl;
609  value = cold_damage().mod;
610  if ( value != 0 )
611  sw() << "\tColdDamageMod\t" << static_cast<int>( value ) << pf_endl;
612  value = energy_damage().mod;
613  if ( value != 0 )
614  sw() << "\tEnergyDamageMod\t" << static_cast<int>( value ) << pf_endl;
615  value = poison_damage().mod;
616  if ( value != 0 )
617  sw() << "\tPoisonDamageMod\t" << static_cast<int>( value ) << pf_endl;
618  value = physical_damage().mod;
619  if ( value != 0 )
620  sw() << "\tPhysicalDamageMod\t" << static_cast<int>( value ) << pf_endl;
621 
622  if ( has_movement_cost() )
623  {
624  auto movecost_value = movement_cost();
625  if ( movecost_value.walk != Core::MovementCostMod::DEFAULT.walk )
626  sw() << "\tMovementWalkMod\t" << static_cast<double>( movecost_value.walk ) << pf_endl;
627  if ( movecost_value.run != Core::MovementCostMod::DEFAULT.run )
628  sw() << "\tMovementRunMod\t" << static_cast<double>( movecost_value.run ) << pf_endl;
629  if ( movecost_value.walk_mounted != Core::MovementCostMod::DEFAULT.walk_mounted )
630  sw() << "\tMovementWalkMountedMod\t" << static_cast<double>( movecost_value.walk_mounted )
631  << pf_endl;
632  if ( movecost_value.run_mounted != Core::MovementCostMod::DEFAULT.run_mounted )
633  sw() << "\tMovementRunMountedMod\t" << static_cast<double>( movecost_value.run_mounted )
634  << pf_endl;
635  }
636  if ( has_carrying_capacity_mod() )
637  sw() << "\tCarryingCapacityMod\t" << static_cast<int>( carrying_capacity_mod() ) << pf_endl;
638 
639 
640  // output Attributes
641  for ( Attribute* pAttr = Attribute::FindAttribute( 0 ); pAttr != nullptr; pAttr = pAttr->next )
642  {
643  const AttributeValue& av = attribute( pAttr->attrid );
644  short lock = av.lock();
645  unsigned cap = av.cap();
646 
647  if ( av.base() || lock ||
648  cap != pAttr->default_cap ) // it kind of floods the file... but... :/ (Nando)
649  {
650  unsigned ones = av.base() / 10;
651  unsigned tenths = av.base() % 10;
652  sw() << "\t" << pAttr->name << "\t" << ones;
653  if ( tenths )
654  sw() << "." << tenths;
655 
656  if ( cap != pAttr->default_cap )
657  {
658  unsigned cap_ones = cap / 10;
659  unsigned cap_tenths = cap % 10;
660 
661  sw() << ":" << cap_ones;
662  if ( tenths )
663  sw() << "." << cap_tenths;
664  }
665 
666  if ( lock )
667  sw() << ";" << lock;
668 
669  sw() << pf_endl;
670  }
671  }
672 
673  // output Vitals
674  for ( Core::Vital* pVital = Core::FindVital( 0 ); pVital != nullptr; pVital = pVital->next )
675  {
676  const VitalValue& vv = vital( pVital->vitalid );
677  if ( vv.current_ones() )
678  {
679  sw() << "\t" << pVital->name << "\t" << vv.current_ones() << pf_endl;
680  }
681  }
682 
683  if ( has_skillstatcap() )
684  {
685  auto cap_value = skillstatcap();
686  if ( cap_value.statcap != Core::SkillStatCap::DEFAULT.statcap )
687  sw() << "\tStatcap\t" << static_cast<int>( cap_value.statcap ) << pf_endl;
688  if ( cap_value.skillcap != Core::SkillStatCap::DEFAULT.skillcap )
689  sw() << "\tSkillcap\t" << static_cast<int>( cap_value.skillcap ) << pf_endl;
690  }
691 
692  if ( has_luck() )
693  sw() << "\tLuck\t" << static_cast<int>( luck() ) << pf_endl;
694  if ( has_followers() )
695  {
696  auto followers_value = followers();
697  if ( followers_value.followers_max != Core::ExtStatBarFollowers::DEFAULT.followers_max )
698  sw() << "\tFollowersMax\t" << static_cast<int>( followers_value.followers_max ) << pf_endl;
699  if ( followers_value.followers != Core::ExtStatBarFollowers::DEFAULT.followers )
700  sw() << "\tFollowers\t" << static_cast<int>( followers_value.followers ) << pf_endl;
701  }
702  if ( has_tithing() )
703  sw() << "\tTithing\t" << static_cast<int>( tithing() ) << pf_endl;
704 
705 
706  if ( movemode != Core::MOVEMODE_LAND )
707  sw() << "\tMoveMode\t" << encode_movemode( movemode ) << pf_endl;
708 
709  if ( !privs.empty() )
710  {
711  sw() << "\tPrivs\t" << privs.extract() << pf_endl;
712  }
713  if ( !settings.empty() )
714  {
715  sw() << "\tSettings\t" << settings.extract() << pf_endl;
716  }
717 
718  sw() << "\tCreatedAt\t" << created_at << pf_endl;
719 
720  if ( has_squelched_until() )
721  sw() << "\tSquelchedUntil\t" << squelched_until() << pf_endl;
722  if ( has_deafened_until() )
723  sw() << "\tDeafenedUntil\t" << deafened_until() << pf_endl;
724 
725  if ( has_title_prefix() )
726  sw() << "\tTitlePrefix\t" << Clib::getencodedquotedstring( title_prefix() ) << pf_endl;
727  if ( has_title_suffix() )
728  sw() << "\tTitleSuffix\t" << Clib::getencodedquotedstring( title_suffix() ) << pf_endl;
729  if ( has_title_guild() )
730  sw() << "\tTitleGuild\t" << Clib::getencodedquotedstring( title_guild() ) << pf_endl;
731  if ( has_title_race() )
732  sw() << "\tTitleRace\t" << Clib::getencodedquotedstring( title_race() ) << pf_endl;
733 
734  if ( is_murderer() )
735  sw() << "\tMurderer\t" << is_murderer() << pf_endl;
736  if ( party_can_loot() )
737  sw() << "\tPartyCanLoot\t" << party_can_loot() << pf_endl;
738  for ( const auto& rt : reportable_ )
739  {
740  sw() << "\tReportable\t" << Clib::hexint( rt.serial ) << " " << rt.polclock << pf_endl;
741  }
742 
743  Core::UCorpse* corpse_obj = static_cast<Core::UCorpse*>( Core::system_find_item( last_corpse ) );
744  if ( corpse_obj != nullptr && !corpse_obj->orphan() )
745  sw() << "\tLastCorpse\t" << last_corpse << pf_endl;
746 }
747 
749 {
751 }
752 
753 const char* Character::classname() const
754 {
755  return "Character";
756 }
757 
759 {
760  base::printOn( sw );
761 }
762 
764 {
765  base::printOn( sw );
766 }
768 {
769  wornitems->print( sw_pc, sw_equip );
770 }
771 
773 {
775 
776  const auto not_found = std::string::npos;
777  if ( str.find( 'L' ) != not_found )
778  mm = static_cast<Core::MOVEMODE>( mm + Core::MOVEMODE_LAND );
779  if ( str.find( 'S' ) != not_found )
780  mm = static_cast<Core::MOVEMODE>( mm + Core::MOVEMODE_SEA );
781  if ( str.find( 'A' ) != not_found )
782  mm = static_cast<Core::MOVEMODE>( mm + Core::MOVEMODE_AIR );
783  if ( str.find( 'F' ) != not_found )
784  mm = static_cast<Core::MOVEMODE>( mm + Core::MOVEMODE_FLY );
785  return mm;
786 }
787 
789 {
790  std::string res;
791  if ( mm & Core::MOVEMODE_LAND )
792  res += "L";
793  if ( mm & Core::MOVEMODE_SEA )
794  res += "S";
795  if ( mm & Core::MOVEMODE_AIR )
796  res += "A";
797  if ( mm & Core::MOVEMODE_FLY )
798  res += "F";
799  return res;
800 }
801 
803 {
804  serial = elem.remove_ulong( "SERIAL" );
805 
806  if ( Plib::systemstate.config.check_integrity )
807  {
809  {
810  ERROR_PRINT.Format( "Character 0x{:X} defined more than once.\n" ) << serial;
811  throw std::runtime_error( "Data integrity error" );
812  }
813  }
816 
817  std::string acctname;
818  if ( elem.remove_prop( "ACCOUNT", &acctname ) )
819  {
820  unsigned short charindex;
821  charindex = elem.remove_ushort( "CHARIDX" );
822 
823  if ( charindex >= Plib::systemstate.config.character_slots )
824  {
825  ERROR_PRINT << "Account " << acctname << ": "
826  << "CHARIDX of " << charindex << " is too high for character serial (0x"
827  << fmt::hexu( serial ) << ")\n";
828 
829  throw std::runtime_error( "Data integrity error" );
830  }
831  Accounts::Account* search_acct = Accounts::find_account( acctname.c_str() );
832  if ( search_acct == nullptr )
833  {
834  ERROR_PRINT << "Character '" << name() << "': "
835  << "Account '" << acctname << "' doesn't exist.\n";
836  throw std::runtime_error( "Data integrity error" );
837  }
838  if ( search_acct->get_character( charindex ) != nullptr )
839  {
840  ERROR_PRINT << "Account " << acctname << " has two characters with CHARIDX of " << charindex
841  << "\n";
842  throw std::runtime_error( "Data integrity error" );
843  }
844 
845  acct.set( search_acct );
846  acct->set_character( charindex, this );
847  }
848 
849  trueobjtype = elem.remove_unsigned( "TRUEOBJTYPE", objtype_ ); // dave 1/30/3
850  graphic = static_cast<u16>( objtype_ );
851 
852  registered_house = elem.remove_ulong( "REGISTEREDHOUSE", 0 );
853 
854  base::readProperties( elem );
855 
856  if ( name_ == "" )
857  {
858  ERROR_PRINT << "Character '0x" << fmt::hexu( serial ) << "' has no name!\n";
859  throw std::runtime_error( "Data integrity error" );
860  }
861  wornitems->serial = serial;
862  wornitems->serial_ext = serial_ext;
864 
865  std::string cmdaccstr = elem.remove_string( "CMDLEVEL", "player" );
866  Core::CmdLevel* cmdlevel_search = Core::find_cmdlevel( cmdaccstr.c_str() );
867  if ( cmdlevel_search == nullptr )
868  elem.throw_error( "Didn't understand cmdlevel of '" + cmdaccstr + "'" );
869  cmdlevel_ = cmdlevel_search->cmdlevel;
870 
871  movemode = decode_movemode( elem.remove_string( "MOVEMODE", "L" ) );
872  concealed_ = static_cast<unsigned char>( elem.remove_ushort(
873  "CONCEALED", 0 ) ); // DAVE changed from remove_bool 11/25. concealed is a char, not a bool!
874  // if (concealed_ > cmdlevel)
875  // concealed_ = cmdlevel;
876 
877  truecolor = elem.remove_ushort( "TRUECOLOR" );
878 
879  mountedsteps_ = elem.remove_ulong( "MOUNTEDSTEPS", 0 );
880 
881  gender = static_cast<Core::UGENDER>( elem.remove_ushort( "GENDER" ) );
882  race = static_cast<Core::URACE>( elem.remove_ushort( "RACE", Core::RACE_HUMAN ) );
883 
884  if ( elem.remove_bool( "DEAD", false ) )
886  if ( elem.remove_bool( "HIDDEN", false ) )
888  if ( elem.remove_bool( "FROZEN", false ) )
890 
891  s16 mod_value = static_cast<s16>( elem.remove_int( "FIRERESISTMOD", 0 ) );
892  if ( mod_value != 0 )
893  fire_resist( fire_resist().setAsMod( mod_value ) );
894  mod_value = static_cast<s16>( elem.remove_int( "COLDRESISTMOD", 0 ) );
895  if ( mod_value != 0 )
896  cold_resist( cold_resist().setAsMod( mod_value ) );
897  mod_value = static_cast<s16>( elem.remove_int( "ENERGYRESISTMOD", 0 ) );
898  if ( mod_value != 0 )
899  energy_resist( energy_resist().setAsMod( mod_value ) );
900  mod_value = static_cast<s16>( elem.remove_int( "POISONRESISTMOD", 0 ) );
901  if ( mod_value != 0 )
902  poison_resist( poison_resist().setAsMod( mod_value ) );
903  mod_value = static_cast<s16>( elem.remove_int( "PHYSICALRESISTMOD", 0 ) );
904  if ( mod_value != 0 )
905  physical_resist( physical_resist().setAsMod( mod_value ) );
906 
907  mod_value = static_cast<s16>( elem.remove_int( "FIREDAMAGEMOD", 0 ) );
908  if ( mod_value != 0 )
909  fire_damage( fire_damage().setAsMod( mod_value ) );
910  mod_value = static_cast<s16>( elem.remove_int( "COLDDAMAGEMOD", 0 ) );
911  if ( mod_value != 0 )
912  cold_damage( cold_damage().setAsMod( mod_value ) );
913  mod_value = static_cast<s16>( elem.remove_int( "ENERGYDAMAGEMOD", 0 ) );
914  if ( mod_value != 0 )
915  energy_damage( energy_damage().setAsMod( mod_value ) );
916  mod_value = static_cast<s16>( elem.remove_int( "POISONDAMAGEMOD", 0 ) );
917  if ( mod_value != 0 )
918  poison_damage( poison_damage().setAsMod( mod_value ) );
919  mod_value = static_cast<s16>( elem.remove_int( "PHYSICALDAMAGEMOD", 0 ) );
920  if ( mod_value != 0 )
921  physical_damage( physical_damage().setAsMod( mod_value ) );
922 
923  movement_cost( Core::MovementCostMod(
924  elem.remove_double( "MovementWalkMod", Core::MovementCostMod::DEFAULT.walk ),
925  elem.remove_double( "MovementRunMod", Core::MovementCostMod::DEFAULT.run ),
926  elem.remove_double( "MovementWalkMountedMod", Core::MovementCostMod::DEFAULT.walk_mounted ),
927  elem.remove_double( "MovementRunMountedMod", Core::MovementCostMod::DEFAULT.run_mounted ) ) );
928 
929  carrying_capacity_mod( static_cast<s16>( elem.remove_int( "CarryingCapacityMod", 0 ) ) );
930 
931  height = Core::settingsManager.ssopt.default_character_height; // no really, height is 9
932 
933  created_at = elem.remove_ulong( "CreatedAt", 0 );
934  squelched_until( elem.remove_ulong( "SquelchedUntil", 0 ) );
935  deafened_until( elem.remove_ulong( "DeafenedUntil", 0 ) );
936 
937  title_prefix( elem.remove_string( "TITLEPREFIX", "" ) );
938  title_suffix( elem.remove_string( "TITLESUFFIX", "" ) );
939  title_guild( elem.remove_string( "TITLEGUILD", "" ) );
940  title_race( elem.remove_string( "TITLERACE", "" ) );
941 
942  unsigned int tmp_guildid;
943  if ( elem.remove_prop( "GUILDID", &tmp_guildid ) )
944  guild( Core::Guild::FindOrCreateGuild( tmp_guildid, serial ) );
945 
946  if ( elem.remove_bool( "MURDERER", false ) )
948  if ( elem.remove_bool( "PARTYCANLOOT", false ) )
950 
951  std::string rt;
952  while ( elem.remove_prop( "REPORTABLE", &rt ) )
953  {
954  ISTRINGSTREAM is( rt );
955  reportable_t rt_t;
956  if ( is >> rt_t.serial >> rt_t.polclock )
957  {
958  reportable_.insert( rt_t );
959  }
960  }
961 
962  uclang = elem.remove_string( "UCLang", "enu" );
963  skillstatcap( Core::SkillStatCap(
964  static_cast<s16>( elem.remove_int( "STATCAP", Core::SkillStatCap::DEFAULT.statcap ) ),
965  static_cast<u16>( elem.remove_int( "SKILLCAP", Core::SkillStatCap::DEFAULT.skillcap ) ) ) );
966  luck( static_cast<s16>( elem.remove_int( "LUCK", 0 ) ) );
967  followers( Core::ExtStatBarFollowers(
968  static_cast<s8>(
970  static_cast<s8>(
971  elem.remove_int( "FOLLOWERSMAX", Core::ExtStatBarFollowers::DEFAULT.followers_max ) ) ) );
972  tithing( elem.remove_int( "TITHING", 0 ) );
973 
974  privs.readfrom( elem.remove_string( "Privs", "" ) );
975  settings.readfrom( elem.remove_string( "Settings", "" ) );
977 }
978 
979 // these are read here to allow NPCs to have "die-roll" type values
981 {
982  // read Attributes
983  for ( Attribute* pAttr = Attribute::FindAttribute( 0 ); pAttr != nullptr; pAttr = pAttr->next )
984  {
985  AttributeValue& av = attribute( pAttr->attrid );
986 
987  for ( unsigned i = 0; i < pAttr->aliases.size(); ++i )
988  {
989  std::string temp;
990  if ( elem.remove_prop( pAttr->aliases[i].c_str(), &temp ) )
991  {
992  // read
993  unsigned int base;
994  unsigned int cap = pAttr->default_cap;
995  unsigned char lock = 0;
996  if ( Core::settingsManager.polvar.DataWrittenBy == 93 &&
998  {
999  unsigned int raw = strtoul( temp.c_str(), nullptr, 10 );
1000  base = Core::raw_to_base( raw );
1001  }
1002  else
1003  {
1004  if ( !Core::settingsManager.polvar.DataWrittenBy &&
1006  {
1007  elem.throw_error( "Pol.txt 'System' element needs to specify CoreVersion" );
1008  }
1009 
1010  const char* pval = temp.c_str();
1011  char* pdot = nullptr;
1012  unsigned int ones = strtoul( pval, &pdot, 10 );
1013  unsigned int tenths = 0;
1014  if ( pdot && *pdot == '.' )
1015  tenths = strtoul( pdot + 1, &pdot, 10 );
1016  base = ones * 10 + tenths;
1017 
1018  // Do we have caps?
1019  if ( pdot && *pdot == ':' )
1020  {
1021  unsigned int cap_ones = strtoul( pdot + 1, &pdot, 10 );
1022  unsigned int cap_tenths = 0;
1023 
1024  // Tenths in cap?
1025  if ( pdot && *pdot == '.' )
1026  cap_tenths = strtoul( pdot + 1, &pdot, 10 );
1027 
1028  cap = cap_ones * 10 + cap_tenths;
1029  }
1030 
1031  if ( pdot && *pdot == ';' )
1032  lock = (unsigned char)strtoul( pdot + 1, nullptr, 10 );
1033  }
1034  if ( /*base < ATTRIBUTE_MIN_BASE ||*/ // ATTRIBUTE_MIN_BASE is currently 0
1035  base > ATTRIBUTE_MAX_BASE )
1036  elem.throw_error( "Character " + Clib::hexint( serial ) + " attribute " +
1037  pAttr->aliases[i] + " is out of range" );
1038  av.base( static_cast<unsigned short>( base ) );
1039 
1040  if ( /*cap < ATTRIBUTE_MIN_BASE ||*/ // ATTRIBUTE_MIN_BASE is currently 0
1041  cap > ATTRIBUTE_MAX_BASE )
1042  elem.throw_error( "Character " + Clib::hexint( serial ) + " attribute cap from " +
1043  pAttr->aliases[i] + " is out of range" );
1044  av.cap( static_cast<unsigned short>( cap ) );
1045 
1046 
1047  if ( lock > 2 ) // FIXME: HardCoded Value
1048  elem.throw_error( "Character " + Clib::hexint( serial ) + " attribute " +
1049  pAttr->aliases[i] + " has illegal lock state!" );
1050 
1051  av.lock( lock );
1052 
1053  break;
1054  }
1055  }
1056  }
1057 
1058  calc_vital_stuff();
1059 
1060  // read Vitals
1061  for ( Core::Vital* pVital = Core::FindVital( 0 ); pVital != nullptr; pVital = pVital->next )
1062  {
1063  VitalValue& vv = vital( pVital->vitalid );
1064  for ( const auto& _i : pVital->aliases )
1065  {
1066  unsigned int temp;
1067  if ( elem.remove_prop( _i.c_str(), &temp ) )
1068  {
1069  // read
1070  // these are always just stored as points
1071  if ( /*temp < Core::VITAL_MIN_VALUE ||*/ // VITAL_MIN_VALUE is currently 0
1072  temp > Core::VITAL_MAX_VALUE )
1073  elem.throw_error( "Character " + Clib::hexint( serial ) + " vital " + _i +
1074  " is out of range" );
1075  vv.current_ones( temp );
1076  break;
1077  }
1078  }
1079  }
1080 }
1081 
1083 {
1084  readCommonProperties( elem );
1085  readAttributesAndVitals( elem );
1086 
1087  last_corpse = elem.remove_ulong( "LastCorpse", 0 );
1088 }
1089 
1090 
1091 bool Character::has_privilege( const char* priv ) const
1092 {
1093  return privs.contains( priv ) || privs.contains( "all" );
1094 }
1095 
1096 bool Character::setting_enabled( const char* setting ) const
1097 {
1098  return cached_settings.get( PRIV_FLAGS::ALL ) || settings.contains( setting );
1099 }
1100 
1102 {
1103  PrivUpdater invulwatch( update ? this : nullptr, PRIV_FLAGS::INVUL );
1104  PrivUpdater seeghostswatch( update ? this : nullptr, PRIV_FLAGS::SEE_GHOSTS );
1105  PrivUpdater seehiddenwatch( update ? this : nullptr, PRIV_FLAGS::SEE_HIDDEN );
1106  PrivUpdater seeinvisitemswatch( update ? this : nullptr, PRIV_FLAGS::SEE_INVIS_ITEMS );
1107 
1109 
1110  if ( setting_enabled( "all" ) )
1111  {
1113  return;
1114  }
1115  if ( setting_enabled( "clotheany" ) )
1117  if ( setting_enabled( "dblclickany" ) )
1119  if ( setting_enabled( "hearghosts" ) )
1121  if ( setting_enabled( "invul" ) )
1123  if ( setting_enabled( "losany" ) )
1125  if ( setting_enabled( "moveany" ) )
1127  if ( setting_enabled( "renameany" ) )
1129  if ( setting_enabled( "seeghosts" ) )
1131  if ( setting_enabled( "seehidden" ) )
1133  if ( setting_enabled( "seeinvisitems" ) )
1135  if ( setting_enabled( "ignoredoors" ) )
1137  if ( setting_enabled( "freemove" ) )
1139  if ( setting_enabled( "firewhilemoving" ) )
1141  if ( setting_enabled( "attackhidden" ) )
1143  if ( setting_enabled( "hiddenattack" ) )
1145  if ( setting_enabled( "plogany" ) )
1147  if ( setting_enabled( "moveanydist" ) )
1149  if ( setting_enabled( "canbeheardasghost" ) )
1151  if ( setting_enabled( "runwhilestealth" ) )
1153  if ( setting_enabled( "speedhack" ) )
1155 }
1156 
1157 void Character::set_setting( const char* setting, bool value )
1158 {
1159  set_dirty();
1160  if ( value == false )
1161  settings.remove( setting );
1162  else if ( has_privilege( setting ) )
1163  settings.add( setting );
1164 
1166 }
1167 
1168 std::string Character::all_settings() const
1169 {
1170  return settings.extract();
1171 }
1172 
1173 std::string Character::all_privs() const
1174 {
1175  return privs.extract();
1176 }
1177 
1178 void Character::set_privs( const std::string& privlist )
1179 {
1180  set_dirty();
1181  privs.readfrom( privlist );
1182 }
1183 
1184 void Character::grant_privilege( const char* priv )
1185 {
1186  if ( !privs.contains( priv ) )
1187  {
1188  set_dirty();
1189  privs.add( priv );
1190  }
1191 }
1192 
1193 void Character::revoke_privilege( const char* priv )
1194 {
1195  set_dirty();
1196  privs.remove( priv );
1197  settings.remove( priv );
1199 }
1200 
1201 bool Character::can_access( const Items::Item* item, int range ) const
1202 {
1203  // TODO: find_legal_item() is awful, we should just check the item
1204  // properties directly instead of going around searching for a given serial in the world
1205 
1206  // Range < 0 has special meaning. -1 is the default accessible range,
1207  // anything smaller ignores the range check.
1208  if ( range == -1 )
1210 
1211  const bool within_range = ( range < -1 ) || pol_distance( this, item ) <= range;
1212  if ( within_range && ( find_legal_item( this, item->serial ) != nullptr ) )
1213  return true;
1214 
1215  return false;
1216 }
1217 
1218 bool Character::can_move( const Items::Item* item ) const
1219 {
1220  if ( item->objtype_ != UOBJ_CORPSE )
1221  {
1222  return cached_settings.get( PRIV_FLAGS::MOVE_ANY ) || item->movable();
1223  }
1224  else
1225  {
1226  return false;
1227  }
1228 }
1229 
1230 bool Character::can_be_renamed_by( const Character* /*chr*/ ) const
1231 {
1232  // consider command levels?
1233  return false;
1234 }
1235 
1236 bool Character::can_rename( const Character* chr ) const
1237 {
1238  return cached_settings.get( PRIV_FLAGS::RENAME_ANY ) || chr->can_be_renamed_by( this );
1239 }
1240 
1241 bool Character::can_clothe( const Character* chr ) const
1242 {
1243  return ( ( chr == this ) || cached_settings.get( PRIV_FLAGS::CLOTHE_ANY ) );
1244 }
1245 
1247 {
1249 }
1250 
1252 {
1254 }
1255 
1257 {
1259 }
1260 
1262 {
1264 }
1265 
1267 {
1269 }
1270 
1272 {
1274 }
1275 
1277 {
1278  return static_cast<Core::UContainer*>( wornitems->GetItemOnLayer( Core::LAYER_BACKPACK ) );
1279 }
1280 
1282 {
1284  if ( _item != nullptr && _item->script_isa( Core::POLCLASS_SPELLBOOK ) )
1285  {
1286  Core::Spellbook* book = static_cast<Core::Spellbook*>( _item );
1287  if ( book->spell_school == school )
1288  return book;
1289  }
1290 
1291  Core::UContainer* cont = backpack();
1292  if ( cont != nullptr )
1293  {
1294  for ( Core::UContainer::const_iterator itr = cont->begin(); itr != cont->end(); ++itr )
1295  {
1296  const Items::Item* item = GET_ITEM_PTR( itr );
1297 
1298  if ( item != nullptr && item->script_isa( Core::POLCLASS_SPELLBOOK ) )
1299  {
1300  const Core::Spellbook* book = static_cast<const Core::Spellbook*>( item );
1301  if ( book->spell_school == school )
1302  return const_cast<Core::Spellbook*>( book );
1303  }
1304  }
1305  }
1306  return nullptr;
1307 }
1308 
1309 unsigned int Character::gold_carried() const
1310 {
1311  Core::UContainer* bp = backpack();
1312  if ( bp != nullptr )
1314  else
1315  return 0;
1316 }
1317 
1318 // TODO: This could be more efficient, by inlining 'spend' logic
1319 // in a recursive function
1320 
1321 void Character::spend_gold( unsigned int amount )
1322 {
1323  passert( gold_carried() >= amount );
1324 
1325  Core::UContainer* bp = backpack();
1326  if ( bp != nullptr )
1328  if ( client != nullptr )
1329  send_full_statmsg( client, this );
1330 }
1331 
1333 {
1334  return wornitems->GetItemOnLayer( layer );
1335 }
1336 
1337 bool Character::layer_is_equipped( int layer ) const
1338 {
1339  return ( wornitems->GetItemOnLayer( layer ) != nullptr );
1340 }
1341 
1342 bool Character::is_equipped( const Items::Item* item ) const
1343 {
1344  if ( !Items::valid_equip_layer( item ) )
1345  return false;
1346 
1347  return ( wornitems->GetItemOnLayer( item->tile_layer ) == item );
1348 }
1349 
1351 {
1352  const Items::ItemDesc& desc = item->itemdesc();
1353  return ( attribute( Core::gamestate.pAttrStrength->attrid ).base() >= desc.base_str_req );
1354 }
1355 
1356 bool Character::equippable( const Items::Item* item ) const
1357 {
1358  if ( !Items::valid_equip_layer( item ) )
1359  {
1360  if ( item->objtype_ == Core::settingsManager.extobj.mount )
1361  {
1362  POLLOG_INFO.Format(
1363  "\nWarning: Character 0x{:X} tried to mount Item 0x{:X}, but it doesn't have a mount "
1364  "graphic (current graphic: 0x{:X}). Check that the list of mounts in uoconvert.cfg is "
1365  "correct and re-run uoconvert if necessary.\n" )
1366  << this->serial << item->serial << item->graphic;
1367  }
1368 
1369  return false;
1370  }
1371  if ( layer_is_equipped( item->tile_layer ) )
1372  {
1373  return false;
1374  }
1375  if ( ( item->tile_layer == Core::LAYER_BACKPACK ) &&
1377  {
1378  return false;
1379  }
1380 
1381  // Only allow mounts if they have the mount objtype as defined in extobj.cfg
1384  {
1385  POLLOG_INFO.Format(
1386  "\nWarning: Character 0x{:X} tried to mount Item 0x{:X}, but it doesn't have the mount "
1387  "objtype (as defined in extobj.cfg) and EnforceMountObjtype in pol.cfg is true.\n" )
1388  << this->serial << item->serial;
1389  return false;
1390  }
1391 
1393  {
1394  return false;
1395  }
1396  // redundant sanity check
1397  if ( Core::tilelayer( item->graphic ) != item->tile_layer )
1398  {
1399  return false;
1400  }
1401 
1402  const Items::ItemDesc& desc = item->itemdesc();
1403  if ( attribute( Core::gamestate.pAttrStrength->attrid ).base() < desc.base_str_req )
1404  {
1405  return false;
1406  }
1407 
1408  if ( item->tile_layer == Core::LAYER_HAND1 || item->tile_layer == Core::LAYER_HAND2 )
1409  {
1410  if ( weapon != nullptr )
1411  {
1413  {
1414  return false;
1415  }
1416  }
1417  if ( item->isa( Core::UOBJ_CLASS::CLASS_WEAPON ) )
1418  {
1419  const Items::UWeapon* wpn_item = static_cast<const Items::UWeapon*>( item );
1420  if ( wpn_item->descriptor().two_handed )
1421  {
1423  {
1424  return false;
1425  }
1426  }
1427  }
1428  }
1429 
1430  return true;
1431 }
1432 
1434 {
1435  passert_r( equippable( item ),
1436  "It is impossible to equip Item with ObjType " + Clib::hexint( item->objtype_ ) );
1437 
1438  wornitems->PutItemOnLayer( item );
1439 
1440  // PutItemOnLayer sets the layer, so we can go on now
1441  // checking item->layer instead of item->tile_layer
1442  if ( item->isa( Core::UOBJ_CLASS::CLASS_WEAPON ) &&
1443  ( item->layer == Core::LAYER_HAND1 || item->layer == Core::LAYER_HAND2 ) )
1444  {
1445  weapon = static_cast<Items::UWeapon*>( item );
1447  }
1448  else if ( item->isa( Core::UOBJ_CLASS::CLASS_ARMOR ) )
1449  {
1450  if ( item->layer == Core::LAYER_HAND1 || item->layer == Core::LAYER_HAND2 )
1451  {
1452  shield = static_cast<Items::UArmor*>( item );
1453  }
1455  }
1456  refresh_ar();
1457 }
1458 
1460 {
1462 }
1463 
1465 {
1466  passert( Items::valid_equip_layer( item ) );
1467  // assume any item being de-equipped is in fact being worn.
1468  passert( item->container == wornitems.get() );
1469  passert( is_equipped( item ) );
1470 
1471  wornitems->RemoveItemFromLayer( item );
1472 
1473  if ( item == weapon )
1474  {
1476  /* we don't reset the swing timer here, 'cause
1477  you can switch from weapon to H2H quickly.
1478  Note, this _could_ let you use a faster weapon
1479  to wrestle faster, hmm.
1480  */
1481  }
1482  else if ( item == shield )
1483  {
1484  shield = nullptr;
1486  }
1487  refresh_ar();
1488 }
1489 
1491 {
1492  if ( race == Core::RACE_GARGOYLE )
1493  return ( movemode & Core::MOVEMODE_FLY ) == 0 ? false : true;
1494 
1496 }
1497 
1498 
1500 {
1501  for ( unsigned layer = Core::LAYER_EQUIP__LOWEST; layer <= Core::LAYER_EQUIP__HIGHEST; layer++ )
1502  {
1503  Items::Item* item = wornitems->GetItemOnLayer( layer );
1504  if ( item )
1505  {
1506  if ( item->serial == find_serial )
1507  return item;
1508  // 4/2007 - MuadDib
1509  // Added cont check and using cont->find to check here
1510  // for equipped cont items like the ML added Quivers.
1511  // Using redundant null check.
1512  if ( item != nullptr && item->script_isa( Core::POLCLASS_CONTAINER ) )
1513  {
1514  if ( layer != Core::LAYER_HAIR && layer != Core::LAYER_FACE && layer != Core::LAYER_BEARD &&
1515  layer != Core::LAYER_BACKPACK && layer != Core::LAYER_MOUNT )
1516  {
1517  Core::UContainer* cont = static_cast<Core::UContainer*>( item );
1518  item = nullptr;
1519  item = cont->find( find_serial );
1520  if ( item != nullptr )
1521  return item;
1522  }
1523  }
1524  }
1525  }
1526  return nullptr;
1527 }
1528 
1529 void Character::produce( const Core::Vital* pVital, VitalValue& vv, unsigned int amt )
1530 {
1531  int start_ones = vv.current_ones();
1532  set_dirty();
1533  vv.produce( amt );
1534  if ( start_ones != vv.current_ones() )
1535  {
1537  }
1538 }
1539 
1540 bool Character::consume( const Core::Vital* pVital, VitalValue& vv, unsigned int amt )
1541 {
1542  bool res;
1543  int start_ones = vv.current_ones();
1544  set_dirty();
1545  res = vv.consume( amt );
1546  if ( start_ones != vv.current_ones() )
1547  {
1549  }
1550  return res;
1551 }
1552 
1553 void Character::set_current_ones( const Core::Vital* pVital, VitalValue& vv, unsigned int ones )
1554 {
1555  set_dirty();
1556  vv.current_ones( ones );
1558 }
1559 
1560 void Character::set_current( const Core::Vital* pVital, VitalValue& vv, unsigned int ones )
1561 {
1562  set_dirty();
1563  vv.current( ones );
1565 }
1566 
1568 {
1569  VitalValue& vv = vital( pVital->vitalid );
1570  int rr = vv.regenrate();
1571  if ( rr > 0 )
1572  {
1573  produce( pVital, vv, rr / 12 );
1574  }
1575  else if ( rr < 0 )
1576  {
1577  consume( pVital, vv, -rr / 12 );
1578  }
1579 }
1580 
1581 void Character::calc_vital_stuff( bool i_mod, bool v_mod )
1582 {
1583  if ( i_mod )
1584  {
1585  for ( unsigned ai = 0; ai < Core::gamestate.numAttributes; ++ai )
1586  {
1588  }
1589  }
1590 
1591  if ( v_mod )
1592  {
1593  for ( unsigned vi = 0; vi < Core::gamestate.numVitals; ++vi )
1594  {
1596  }
1597  }
1598 }
1599 
1601 {
1602  VitalValue& vv = vital( pVital->vitalid );
1603 
1604  int start_ones = vv.current_ones();
1605  int start_max = vv.maximum_ones();
1606 
1607  // dave change the order of maximum and regen function 3/19/3
1608  int mv = pVital->get_maximum_func->call_long( new Module::ECharacterRefObjImp( this ) );
1609 
1610  if ( mv < static_cast<int>( Core::VITAL_LOWEST_MAX_HUNDREDTHS ) )
1612  if ( mv > static_cast<int>( Core::VITAL_HIGHEST_MAX_HUNDREDTHS ) )
1614 
1615  vv.maximum( mv );
1616 
1617  int rr = pVital->get_regenrate_func->call_long( new Module::ECharacterRefObjImp( this ) );
1618 
1619  if ( rr < Core::VITAL_LOWEST_REGENRATE )
1621  if ( rr > Core::VITAL_HIGHEST_REGENRATE )
1623 
1624  vv.regenrate( rr );
1625 
1626  if ( ( start_ones != vv.current_ones() ) || ( start_max != vv.maximum_ones() ) )
1628 }
1629 
1631 {
1632  AttributeValue& av = attribute( pAttr->attrid );
1633 
1634  if ( pAttr->getintrinsicmod_func )
1635  {
1636  int im = pAttr->getintrinsicmod_func->call_long( new Module::ECharacterRefObjImp( this ) );
1637 
1638  if ( im < ATTRIBUTE_MIN_INTRINSIC_MOD )
1640  if ( im > ATTRIBUTE_MAX_INTRINSIC_MOD )
1642 
1643  av.intrinsic_mod( static_cast<short>( im ) );
1644  }
1645 }
1646 
1648 {
1649  set_dirty();
1650  for ( unsigned vi = 0; vi < Core::gamestate.numVitals; ++vi )
1651  {
1652  VitalValue& vv = vital( vi );
1653  vv.current( vv.maximum() );
1654 
1656  }
1657 }
1658 
1659 bool Character::setgraphic( u16 newgraphic )
1660 {
1661  if ( newgraphic < 1 ||
1662  newgraphic >
1663  0x800 ) // Maximum graphic: 2048, changed to allow new graphics -- Nando - 2009-01-14
1664  return false;
1665 
1666  set_dirty();
1667  graphic = newgraphic;
1669  if ( client )
1670  send_goxyz( client, client->chr );
1672 
1673  return true;
1674 }
1675 
1677 {
1679  if ( client )
1680  send_goxyz( client, client->chr );
1682 }
1683 
1685 {
1687 
1688  // only if client is active or for npcs
1689  if ( ( client ) || ( this->isa( Core::UOBJ_CLASS::CLASS_NPC ) ) )
1690  {
1691  if ( client )
1692  {
1693  send_goxyz( client, client->chr );
1694  // if poisoned send_goxyz handles 0x17 packet
1695  if ( !poisoned() )
1697  }
1698  // This is a KR only packet, so transmit it only to KR clients
1699  // who are in range.
1700  // if poisoned send_move_mobile_to_nearby_cansee handles 0x17 packet
1701  if ( !poisoned() )
1702  {
1703  Network::HealthBarStatusUpdate msg( serial_ext, Network::HealthBarStatusUpdate::Color::GREEN,
1704  poisoned() );
1706  this, [&]( Character* zonechr ) { msg.Send( zonechr->client ); } );
1707  }
1708  }
1709 }
1710 
1712 {
1713  if ( hidden() )
1714  {
1715  set_stealthsteps( 0 );
1716  if ( client )
1717  send_move( client, this );
1720  }
1721  else
1722  {
1723  unhide();
1724  set_stealthsteps( 0 );
1725  }
1726 }
1727 
1729 {
1730  if ( concealed() )
1731  {
1732  if ( client )
1733  send_move( client, this );
1736  }
1737  else if ( is_visible() )
1738  unhide();
1739  set_stealthsteps( 0 );
1740 }
1741 
1743 {
1746 }
1747 
1749 {
1750  if ( client )
1751  send_goxyz( client, client->chr );
1753 }
1754 
1756 {
1757  if ( client )
1758  {
1760  {
1762  }
1763  }
1764 }
1765 
1766 void Character::setfacing( u8 newfacing )
1767 {
1768  facing = newfacing & 7;
1769 }
1770 
1772 {
1773  // Breaks paperdoll
1774  u8 flag1 = 0;
1775  if ( gender )
1776  flag1 |= Core::CHAR_FLAG1_GENDER;
1777  if ( ( poisoned() ) &&
1778  ( ~other_client->ClientType &
1779  Network::CLIENTTYPE_7000 ) ) // client >=7 receive the poisonflag with 0x17
1780  flag1 |= Core::CHAR_FLAG1_POISONED;
1781  if ( ( movemode & Core::MOVEMODE_FLY ) &&
1782  ( other_client->ClientType & Network::CLIENTTYPE_7000 ) )
1783  flag1 |= Core::CHAR_FLAG1_FLYING;
1784  if ( ( Core::settingsManager.ssopt.invul_tag == 2 ) && ( invul() ) )
1786  if ( warmode() )
1787  flag1 |= Core::CHAR_FLAG1_WARMODE;
1788  if ( !is_visible() )
1789  flag1 |= Core::CHAR_FLAG1_INVISIBLE;
1790 
1791  return flag1;
1792 }
1793 
1794 void Character::apply_raw_damage_hundredths( unsigned int amount, Character* source, bool userepsys,
1795  bool send_damage_packet )
1796 {
1797  if ( dead() )
1798  {
1799  // cerr << "Waah! " << name() << " " << hexint(serial) << " is dead, but taking damage?" <<
1800  // endl;
1801  return;
1802  }
1803 
1804  if ( ( source ) && ( userepsys ) )
1805  source->repsys_on_attack( this );
1806 
1807  if ( ( amount == 0 ) || cached_settings.get( PRIV_FLAGS::INVUL ) )
1808  return;
1809 
1810  set_dirty();
1811  if ( hidden() )
1812  unhide();
1813 
1814  if ( send_damage_packet && source )
1815  {
1816  u16 showdmg;
1817  if ( amount > 6553500 ) // 0xFFFF*100
1818  showdmg = 0xFFFF;
1819  else
1820  showdmg = static_cast<u16>( amount / 100 );
1821  send_damage( source, this, showdmg );
1822  }
1823 
1824  if ( paralyzed() )
1826 
1827  disable_regeneration_for( 2 ); // FIXME depend on amount?
1828 
1829  // 0.xx is still 0
1830  VitalValue& vv = vital( Core::gamestate.pVitalLife->vitalid );
1831  if ( vv.current() - amount <= 99 )
1832  amount = vv.current(); // be greedy with that last point
1833  consume( Core::gamestate.pVitalLife, vv, amount );
1834 
1835  if ( ( source ) && ( userepsys ) )
1836  source->repsys_on_damage( this );
1837 
1839 
1840  if ( vv.current() == 0 )
1841  die();
1842 }
1843 
1844 // keep this in sync with NPC::armor_absorb_damage
1845 
1846 
1847 unsigned short calc_thru_damage( double damage, unsigned short ar )
1848 {
1849  int blocked = ar;
1850  if ( blocked < 0 )
1851  blocked = 0;
1852 
1853  int absorbed = blocked / 2;
1854 
1855  blocked -= absorbed;
1856  absorbed += Clib::random_int( blocked );
1857  damage -= absorbed;
1858 
1859  if ( damage >= 2.0 )
1860  {
1861  return static_cast<unsigned short>( damage * 0.5 );
1862  }
1863  else
1864  {
1865  int dmg = static_cast<int>( damage );
1866  if ( dmg >= 0 )
1867  return static_cast<unsigned short>( dmg );
1868  else
1869  return 0;
1870  }
1871 }
1872 
1873 
1874 double Character::armor_absorb_damage( double damage )
1875 {
1876  Items::UArmor* armor = choose_armor();
1877  if ( armor != nullptr )
1878  {
1879  damage = calc_thru_damage( damage, armor->ar() + ar_mod() );
1880 
1881  armor->reduce_hp_from_hit();
1882  }
1883  return damage;
1884 }
1885 
1886 double Character::apply_damage( double damage, Character* source, bool userepsys,
1887  bool send_damage_packet )
1888 {
1889  damage = armor_absorb_damage( damage );
1890  if ( Core::settingsManager.watch.combat )
1891  INFO_PRINT << "Final damage: " << damage << "\n";
1892  do_imhit_effects();
1893  apply_raw_damage_hundredths( static_cast<unsigned int>( damage * 100 ), source, userepsys,
1894  send_damage_packet );
1895 
1896  return damage;
1897 }
1898 
1899 void Character::get_hitscript_params( double damage, Items::UArmor** parmor,
1900  unsigned short* rawdamage )
1901 {
1902  Items::UArmor* armor = choose_armor();
1903  if ( armor )
1904  {
1905  *rawdamage = calc_thru_damage( damage, armor->ar() + ar_mod() );
1906  }
1907  else
1908  {
1909  *rawdamage = static_cast<unsigned short>( damage );
1910  }
1911  *parmor = armor;
1912 }
1913 
1914 void Character::run_hit_script( Character* defender, double damage )
1915 {
1918  if ( prog.get() == nullptr )
1919  return;
1920 
1921  std::unique_ptr<Core::UOExecutor> ex( Core::create_script_executor() );
1922  auto uoemod = new Module::UOExecutorModule( *ex );
1923  ex->addModule( uoemod );
1924 
1925  unsigned short rawdamage = 0;
1926  unsigned short basedamage = static_cast<unsigned short>( damage );
1927 
1928  Items::UArmor* armor = nullptr;
1929 
1930  defender->get_hitscript_params( damage, &armor, &rawdamage );
1931 
1932 
1933  ex->pushArg( new Bscript::BLong( rawdamage ) );
1934  ex->pushArg( new Bscript::BLong( basedamage ) );
1935  if ( armor )
1936  ex->pushArg( new Module::EItemRefObjImp( armor ) );
1937  else
1938  ex->pushArg( new Bscript::BLong( 0 ) );
1939  ex->pushArg( new Module::EItemRefObjImp( weapon ) );
1940  ex->pushArg( new Module::ECharacterRefObjImp( defender ) );
1941  ex->pushArg( new Module::ECharacterRefObjImp( this ) );
1942 
1943  ex->os_module->priority = 100;
1944 
1945  if ( ex->setProgram( prog.get() ) )
1946  {
1947  uoemod->controller_.set( this );
1948  schedule_executor( ex.release() );
1949  }
1950  else
1951  {
1952  POLLOG << "Blech, couldn't start hitscript " << weapon->hit_script().name() << "\n";
1953  }
1954 }
1955 
1963 {
1964  if ( vital( Core::gamestate.pVitalLife->vitalid ).is_at_maximum() && !poisoned() && !paralyzed() )
1965  {
1967  }
1968 }
1969 
1970 
1979 void Character::heal_damage_hundredths( unsigned int amount )
1980 {
1981  if ( dead() )
1982  {
1983  // cerr << "Waah! " << name() << " is dead, but healing damage?" << endl;
1984  return;
1985  }
1986 
1987  if ( amount == 0 )
1988  return;
1989 
1990  produce( Core::gamestate.pVitalLife, vital( Core::gamestate.pVitalLife->vitalid ), amount );
1991 
1992  check_undamaged();
1993 
1995 }
1996 
1998 {
2000  item->layer = Core::LAYER_ROBE_DRESS;
2001  return item;
2002 }
2004 {
2006  item->layer = Core::LAYER_ROBE_DRESS;
2007  return item;
2008 }
2010 {
2012  item->layer = Core::LAYER_BACKPACK;
2013  return item;
2014 }
2015 
2016 
2018 {
2020  msg->Write<u8>( warmode() ? 1u : 0u );
2021  msg->offset++; // u8 unk2
2022  msg->Write<u8>( 0x32u );
2023  msg->offset++; // u8 unk4
2024  msg.Send( client );
2025 }
2026 
2028 {
2029  if ( !inrange( chr, client->chr ) )
2030  return;
2031 
2032  if ( !client->chr->is_visible_to_me( chr ) )
2033  {
2034  send_remove_character( client, chr );
2035  }
2036 }
2038 {
2039  if ( !inrange( chr, client->chr ) )
2040  return;
2041 
2042  if ( chr->dead() && client->chr->is_visible_to_me( chr ) )
2043  {
2044  send_owncreate( client, chr );
2045  }
2046 }
2047 
2049 {
2050  if ( !dead() )
2051  {
2052  ERROR_PRINT << "uh, trying to resurrect " << name() << ", who isn't dead.\n";
2053  return;
2054  }
2055  set_dirty();
2056  if ( graphic == UOBJ_HUMAN_MALE_GHOST )
2058  else if ( graphic == UOBJ_HUMAN_FEMALE_GHOST )
2060  else if ( graphic == UOBJ_ELF_MALE_GHOST )
2062  else if ( graphic == UOBJ_ELF_FEMALE_GHOST )
2064  else if ( graphic == UOBJ_GARGOYLE_MALE_GHOST )
2066  else if ( graphic == UOBJ_GARGOYLE_FEMALE_GHOST )
2068 
2073 
2074  color = truecolor;
2075 
2076  if ( Core::gamestate.pVitalLife->regen_while_dead )
2077  {
2078  VitalValue& vv = vital( Core::gamestate.pVitalLife->vitalid );
2079  if ( vv._current == 0 ) // set in die()
2080  set_current_ones( Core::gamestate.pVitalLife, vv, 1 );
2081  }
2082  else
2083  set_current_ones( Core::gamestate.pVitalLife, vital( Core::gamestate.pVitalLife->vitalid ), 1 );
2084 
2085  if ( !Core::gamestate.pVitalMana->regen_while_dead )
2086  set_current_ones( Core::gamestate.pVitalMana, vital( Core::gamestate.pVitalMana->vitalid ), 0 );
2087 
2088  if ( !Core::gamestate.pVitalStamina->regen_while_dead )
2089  set_current_ones( Core::gamestate.pVitalStamina,
2090  vital( Core::gamestate.pVitalStamina->vitalid ), 1 );
2091 
2092  // Replace the death shroud with a death robe
2093  bool equip_death_robe = true;
2095  {
2096  Items::Item* death_shroud = wornitems->GetItemOnLayer( Core::LAYER_ROBE_DRESS );
2097  if ( death_shroud->objtype_ == UOBJ_DEATH_SHROUD )
2098  {
2099  unequip( death_shroud );
2100  death_shroud->destroy();
2101  death_shroud = nullptr;
2102  }
2103  else
2104  {
2105  // Do not destroy and replace the already equipped robe
2106  equip_death_robe = false;
2107  }
2108  }
2109  if ( equip_death_robe )
2110  {
2111  Items::Item* death_robe = create_death_robe();
2112  death_robe->realm = realm;
2113  equip( death_robe );
2114  }
2115 
2116  // equip( create_backpack() );
2117 
2118  // if this has a connected client, tell him his new position.
2119  if ( client )
2120  {
2121  client->pause();
2122  send_warmode();
2123  send_goxyz( client, this );
2124  send_owncreate( client, this );
2126  send_remove_if_hidden_ghost( zonechr, client );
2127  } );
2128  client->restart();
2129  }
2130 
2131  // Tell other connected players, if in range, about this character.
2134  realm->notify_resurrected( *this );
2135 }
2136 
2138 {
2139  Items::Item* death_shroud = create_death_shroud();
2140  death_shroud->realm = realm;
2141  if ( equippable( death_shroud ) ) // check it or passert will trigger
2142  {
2143  equip( death_shroud );
2144  send_wornitem_to_inrange( this, death_shroud );
2145  }
2146  else
2147  {
2148  ERROR_PRINT.Format( "Create Character: Failed to equip death shroud 0x{:X}\n" )
2149  << death_shroud->graphic;
2150  death_shroud->destroy();
2151  }
2152 
2153  if ( client != nullptr )
2154  {
2155  if ( opponent_ )
2156  opponent_->inform_disengaged( this );
2157 
2158  client->pause();
2159  send_warmode();
2160 
2161  // Sends the complete corpse to the client itself, so he knows where his
2162  // items went.
2163  send_full_corpse( client, corpse );
2164 
2165  send_goxyz( client, this );
2167  client->chr, [&]( Character* zonechr ) { send_create_ghost( zonechr, client ); } );
2168 
2169  client->restart();
2170  }
2171 
2172  // change self to ghost for ghosts, remove self for living
2174 
2176 
2177  if ( Clib::FileExists( "scripts/misc/chrdeath.ecl" ) )
2178  Core::start_script( "misc/chrdeath", new Module::EItemRefObjImp( corpse ),
2179  new Module::ECharacterRefObjImp( this ) );
2180 }
2181 
2183 {
2184  while ( !opponent_of.empty() )
2185  {
2186  Character* chr = *opponent_of.begin();
2187  // note that chr->set_opponent is going to remove
2188  // its entry from our opponent_of collection,
2189  // so eventually this loop will exit.
2190  chr->set_opponent( nullptr, false );
2191  }
2192 }
2193 
2195 {
2196  if ( Core::gamestate.system_hooks.can_die != nullptr )
2197  {
2198  if ( !Core::gamestate.system_hooks.can_die->call( make_mobileref( this ) ) )
2199  return;
2200  }
2201 
2202  set_current_ones( Core::gamestate.pVitalLife, vital( Core::gamestate.pVitalLife->vitalid ), 0 );
2206 
2207 
2208  u16 save_graphic = graphic;
2209 
2213  {
2214  switch ( race )
2215  {
2216  case Core::RACE_HUMAN:
2218  break;
2219  case Core::RACE_ELF:
2221  break;
2222  case Core::RACE_GARGOYLE:
2223  graphic =
2225  break;
2226  }
2227  }
2229 
2234 
2236  /* FIXME: corpse container difficulties.
2237 
2238  What am I gonna do about the corpse. I've said that
2239  MAX_CONTAINER_ITEMS can be in a container, but if I put
2240  worn items, plus what's in the backpack, in the
2241  corpse 'container' I'm going to violate this. If
2242  I put everything in a backpack in the corpse,
2243  it's too easy to grab everything.
2244  Maybe I have to limit the backpack to MAX_CONTAINER_ITEM
2245  - NUM_LAYERS or something, or grow the "send container"
2246  message to be able to hold a full backpack, plus
2247  all worn items. That doesn't work, tho, 'cause it
2248  overfills the corpse container. ick.
2249 
2250  The current solution is to put the backpack
2251  on the corpse.
2252  */
2253 
2254  Core::UCorpse* corpse = static_cast<Core::UCorpse*>( Items::Item::create( UOBJ_CORPSE ) );
2255  this->last_corpse = corpse->serial;
2256 
2257  corpse->ownerserial = this->serial;
2258  corpse->setname( "A corpse of " + name_.get() );
2259  corpse->take_contents_to_grave( acct == nullptr );
2260 
2262 
2263  corpse->color = truecolor;
2264  corpse->x = x;
2265  corpse->y = y;
2266  corpse->z = z;
2267  corpse->realm = realm;
2268  corpse->facing = facing;
2269  corpse->corpsetype = save_graphic;
2270  // corpse->dir = dir;
2272 
2274  if ( is_trading() )
2275  Core::cancel_trade( this );
2277  corpse->copyprops( *this );
2279 
2280  // Change the character's color to grey
2281  color = 0;
2283 
2284  // small lambdas to reduce the mess inside the loops
2285  auto _copy_item = [&]( Items::Item* _item ) { // copy a item into the corpse
2286  Items::Item* copy = _item->clone();
2287  copy->invisible( true );
2288  copy->movable( false );
2289  corpse->add( copy );
2290  };
2291  auto _drop_item_to_world = [&]( Items::Item* _item ) { // places the item onto the corpse coords
2292  _item->x = corpse->x;
2293  _item->y = corpse->y;
2294  _item->z = corpse->z;
2295  add_item_to_world( _item );
2297  move_item( _item, corpse->x, corpse->y, corpse->z, nullptr );
2298  };
2299 
2300  // WARNING: never ever touch or be 10000% sure what you are doing!!!!
2301  for ( unsigned layer = Core::LAYER_EQUIP__LOWEST; layer <= Core::LAYER_EQUIP__HIGHEST; ++layer )
2302  {
2303  Items::Item* item = wornitems->GetItemOnLayer( layer );
2304  if ( item == nullptr )
2305  continue;
2306  if ( item->layer == Core::LAYER_BACKPACK ) // These needs to be the first!!!!
2307  continue;
2308  // never ever touch this order
2309  // first only copy the hair layers and only these!
2310  // then check for newbie and then I dont care
2311  if ( item->layer == Core::LAYER_BEARD || item->layer == Core::LAYER_HAIR ||
2312  item->layer == Core::LAYER_FACE )
2313  {
2314  // Copies hair items onto the corpse
2315  _copy_item( item );
2316  continue;
2317  }
2318  if ( item->newbie() || item->insured() || item->no_drop() )
2319  continue;
2320  else if ( item->layer != Core::LAYER_MOUNT && item->layer != Core::LAYER_ROBE_DRESS &&
2321  !item->movable() ) // dress layer needs to be unequipped for deathrobe
2322  {
2323  _copy_item( item );
2324  continue;
2325  }
2331  if ( Core::settingsManager.ssopt.honor_unequip_script_on_death )
2332  {
2333  if ( !item->check_unequiptest_scripts() )
2334  continue;
2335  if ( !item->check_unequip_script() )
2336  continue;
2337  }
2338  else
2339  {
2340  item->check_unequip_script();
2341  }
2343  unequip( item );
2345 
2346  u8 newSlot = 1;
2347  if ( !corpse->can_add_to_slot( newSlot ) || !item->slot_index( newSlot ) )
2348  {
2349  _drop_item_to_world( item );
2350  }
2351  else
2352  {
2353  corpse->add_at_random_location( item );
2354  }
2356  }
2358 
2359  // For some reason, the backpack shows up as a small child.. So change its layer.
2360  Core::UContainer* bp = backpack();
2361  if ( bp )
2362  {
2365  bp->extract( tmp );
2367  // We set slot to 1 outside the loop. As it cycles through, this will continue
2368  // to increase. This will reduce the amount of checks to find next available
2369  // slots
2370  u8 packSlot = 1;
2371  // u8 corpseSlot = 1;
2372  while ( !tmp.empty() )
2373  {
2374  Items::Item* bp_item = ITEM_ELEM_PTR( tmp.back() );
2375  tmp.pop_back();
2376  bp_item->container = nullptr;
2377  bp_item->layer = 0;
2379  if ( ( bp_item->newbie() || bp_item->no_drop() || bp_item->use_insurance() ) &&
2380  bp->can_add( *bp_item ) )
2381  {
2382  if ( !bp->can_add_to_slot( packSlot ) || !bp_item->slot_index( packSlot ) )
2383  {
2384  _drop_item_to_world( bp_item );
2385  }
2386  else
2387  {
2388  bp->add( bp_item );
2389  }
2391  }
2392  else if ( corpse->can_add( *bp_item ) )
2393  {
2394  if ( !corpse->can_add_to_slot( packSlot ) || !bp_item->slot_index( packSlot ) )
2395  {
2396  _drop_item_to_world( bp_item );
2397  }
2398  else
2399  {
2400  corpse->add_at_random_location( bp_item );
2401  }
2403  }
2404  else
2405  {
2407  _drop_item_to_world( bp_item );
2408  }
2410  }
2411 
2413 
2414  for ( unsigned layer = Core::LAYER_EQUIP__LOWEST; layer <= Core::LAYER_EQUIP__HIGHEST; ++layer )
2415  {
2416  Items::Item* item = wornitems->GetItemOnLayer( layer );
2417  if ( item == nullptr )
2418  continue;
2419  if ( item->layer == Core::LAYER_BACKPACK ) // These needs to be the first!!!!
2420  continue;
2421  if ( item->layer == Core::LAYER_BEARD || item->layer == Core::LAYER_HAIR ||
2422  item->layer == Core::LAYER_FACE )
2423  continue;
2424  if ( item->layer != Core::LAYER_MOUNT && item->layer != Core::LAYER_ROBE_DRESS &&
2425  !item->movable() )
2426  continue;
2427  if ( ( item->newbie() || item->no_drop() || item->use_insurance() ) && bp->can_add( *item ) )
2428  {
2430  if ( Core::settingsManager.ssopt.honor_unequip_script_on_death )
2431  {
2432  if ( !item->check_unequiptest_scripts() )
2433  continue;
2434  if ( !item->check_unequip_script() )
2435  continue;
2436  }
2437  else
2438  {
2439  item->check_unequip_script();
2440  }
2442  unequip( item );
2443  item->layer = 0;
2445  if ( !bp->can_add_to_slot( packSlot ) || !item->slot_index( packSlot ) )
2446  {
2447  _drop_item_to_world( item );
2448  }
2449  else
2450  {
2451  bp->add_at_random_location( item );
2452  update_item_to_inrange( item );
2453  }
2455  }
2456  }
2458  }
2459 
2460 
2462  send_death_message( this, corpse );
2463 
2465  corpse->restart_decay_timer();
2467  add_item_to_world( corpse );
2469  send_item_to_inrange( corpse );
2470 
2472 
2474 
2475  set_opponent( nullptr );
2476 
2478 
2479  on_death( corpse );
2480 
2481  CLEAR_CHECKPOINT();
2482 }
2483 
2485 {
2486  // find_armor(); <-- MuadDib commented out, put code inside here to cut down on iter.
2487  // Figure out what's in each zone
2488  // FIXME? NZONES * NLAYERS (5 * 24 = 124) iterations.
2489  // okay, reverse, for each wornitem, for each coverage area, upgrade.
2490  // Turley: should be fixed now only iterators over armor's coverage zones instead of all zones
2491  for ( unsigned zone = 0; zone < Core::gamestate.armorzones.size(); ++zone )
2492  armor_[zone] = nullptr;
2493  // we need to reset each resist to 0, then add the base back using calc.
2495 
2496  for ( unsigned layer = Core::LAYER_EQUIP__LOWEST; layer <= Core::LAYER_EQUIP__HIGHEST; ++layer )
2497  {
2498  Items::Item* item = wornitems->GetItemOnLayer( layer );
2499  if ( item == nullptr )
2500  continue;
2501  // Let's check all items as base, and handle their element_resists.
2502  updateEquipableProperties( item );
2503 
2504  if ( item->isa( Core::UOBJ_CLASS::CLASS_ARMOR ) )
2505  {
2506  Items::UArmor* armor = static_cast<Items::UArmor*>( item );
2507  std::set<unsigned short> tmplzones = armor->tmplzones();
2508  std::set<unsigned short>::iterator itr;
2509  for ( itr = tmplzones.begin(); itr != tmplzones.end(); ++itr )
2510  {
2511  if ( ( armor_[*itr] == nullptr ) || ( armor->ar() > armor_[*itr]->ar() ) )
2512  armor_[*itr] = armor;
2513  }
2514  }
2515  }
2516 
2517  // calculate_ar(); <-- MuadDib Commented out, mixed code within ported find_armor to reduce
2518  // iter.
2519  double new_ar = 0.0;
2520  for ( unsigned zone = 0; zone < Core::gamestate.armorzones.size(); ++zone )
2521  {
2522  Items::UArmor* armor = armor_[zone];
2523  if ( armor != nullptr )
2524  {
2525  new_ar += armor->ar() * Core::gamestate.armorzones[zone].chance;
2526  }
2527  }
2528 
2529  /* add AR due to shield : parry skill / 2 is percent of AR */
2530  // FIXME: Should we allow this to be adjustable via a prop? Hrmmmmm
2531  if ( shield != nullptr )
2532  {
2533  double add =
2534  0.5 * 0.01 * shield->ar() * attribute( Core::gamestate.pAttrParry->attrid ).effective();
2535  if ( add > 1.0 )
2536  new_ar += add;
2537  else
2538  new_ar += 1.0;
2539  }
2540 
2541  new_ar += ar_mod();
2542 
2543  short s_new_ar = static_cast<short>( new_ar );
2544  if ( s_new_ar >= 0 )
2545  ar_ = s_new_ar;
2546  else
2547  ar_ = 0;
2548 
2549  if ( client != nullptr )
2550  { // CHECKME consider sending less frequently
2551  send_full_statmsg( client, this );
2552  }
2553 }
2554 
2556 {
2557  if ( item->has_fire_resist() )
2558  fire_resist( fire_resist().addToValue( item->fire_resist() ) );
2559  if ( item->has_cold_resist() )
2560  cold_resist( cold_resist().addToValue( item->cold_resist() ) );
2561  if ( item->has_energy_resist() )
2562  energy_resist( energy_resist().addToValue( item->energy_resist() ) );
2563  if ( item->has_poison_resist() )
2564  poison_resist( poison_resist().addToValue( item->poison_resist() ) );
2565  if ( item->has_physical_resist() )
2566  physical_resist( physical_resist().addToValue( item->physical_resist() ) );
2567 
2568  if ( item->has_fire_damage() )
2569  fire_damage( fire_damage().addToValue( item->fire_damage() ) );
2570  if ( item->has_cold_damage() )
2571  cold_damage( cold_damage().addToValue( item->cold_damage() ) );
2572  if ( item->has_energy_damage() )
2573  energy_damage( energy_damage().addToValue( item->energy_damage() ) );
2574  if ( item->has_poison_damage() )
2575  poison_damage( poison_damage().addToValue( item->poison_damage() ) );
2576  if ( item->has_physical_damage() )
2577  physical_damage( physical_damage().addToValue( item->physical_damage() ) );
2578 }
2579 
2581 {
2582  if ( has_fire_resist() )
2583  fire_resist( fire_resist().resetModAsValue() );
2584  if ( has_cold_resist() )
2585  cold_resist( cold_resist().resetModAsValue() );
2586  if ( has_energy_resist() )
2587  energy_resist( energy_resist().resetModAsValue() );
2588  if ( has_poison_resist() )
2589  poison_resist( poison_resist().resetModAsValue() );
2590  if ( has_physical_resist() )
2591  physical_resist( physical_resist().resetModAsValue() );
2592 
2593  if ( has_fire_damage() )
2594  fire_damage( fire_damage().resetModAsValue() );
2595  if ( has_cold_damage() )
2596  cold_damage( cold_damage().resetModAsValue() );
2597  if ( has_energy_damage() )
2598  energy_damage( energy_damage().resetModAsValue() );
2599  if ( has_poison_damage() )
2600  poison_damage( poison_damage().resetModAsValue() );
2601  if ( has_physical_damage() )
2602  physical_damage( physical_damage().resetModAsValue() );
2603 }
2604 
2606 {
2607  if ( client != nullptr )
2608  {
2609  Core::send_sysmessage( client, "Your armor coverage:" );
2610  for ( unsigned i = 0; i < armor_.size(); ++i )
2611  {
2612  std::string text = Core::gamestate.armorzones[i].name + ": ";
2613  if ( armor_[i] == nullptr )
2614  text += "Nothing";
2615  else
2616  text += armor_[i]->name();
2617  Core::send_sysmessage( client, text );
2618  }
2619  }
2620 }
2621 
2622 /* check skill: test skill, advance, reset atrophy timers, blah blah..
2623  obviously, needs work, and more parameters.
2624  */
2625 
2626 bool Character::check_skill( Core::USKILLID skillid, int difficulty, unsigned short pointvalue )
2627 {
2628  INC_PROFILEVAR( skill_checks );
2629  static bool in_here = false;
2630  if ( !in_here && Core::gamestate.system_hooks.check_skill_hook != nullptr )
2631  {
2632  in_here = true;
2634  new Module::ECharacterRefObjImp( this ), new Bscript::BLong( skillid ),
2635  new Bscript::BLong( difficulty ), new Bscript::BLong( pointvalue ) );
2636  in_here = false;
2637  return res;
2638  }
2639  else
2640  {
2641  return false;
2642  }
2643 }
2644 
2646 {
2647  if ( concealed() > cmdlevel() )
2648  concealed( cmdlevel() );
2649 }
2650 
2651 // you can only be concealed from
2652 // those of lower stature
2654 {
2655  return ( chr->concealed() > cmdlevel() );
2656 }
2657 
2658 bool Character::is_visible_to_me( const Character* chr ) const
2659 {
2660  if ( chr == nullptr )
2661  return false;
2662  if ( chr == this )
2663  return true; // I can always see myself (?)
2664  if ( is_concealed_from_me( chr ) )
2665  return false;
2666 
2667  if ( chr->realm != this->realm )
2668  return false; // noone can see across different realms.
2669  if ( !chr->logged_in() )
2670  return false;
2671  if ( chr->hidden() && !cached_settings.get( PRIV_FLAGS::SEE_HIDDEN ) )
2672  return false; // noone can see anyone hidden.
2673  if ( dead() )
2674  return true; // If I'm dead, I can see anything
2675  if ( !chr->dead() || cached_settings.get( PRIV_FLAGS::SEE_GHOSTS ) )
2676  return true; // Anyone can see the living
2677  if ( chr->warmode() )
2678  return true; // Anyone can see someone in warmode
2679  return false;
2680 };
2681 
2682 // NOTE: chr is at new position, lastx/lasty have old position.
2683 void PropagateMove( /*Client *client,*/ Character* chr )
2684 {
2685  using namespace Network;
2686  if ( chr == nullptr )
2687  return;
2688  RemoveObjectPkt msgremove( chr->serial_ext );
2689  HealthBarStatusUpdate msgpoison( chr->serial_ext, HealthBarStatusUpdate::Color::GREEN,
2690  chr->poisoned() );
2691  HealthBarStatusUpdate msginvul( chr->serial_ext, HealthBarStatusUpdate::Color::YELLOW,
2692  chr->invul() );
2694  MoveChrPkt msgmove( chr );
2695  build_owncreate( chr, msgcreate.Get() );
2696 
2698  Client* client = zonechr->client;
2699  if ( zonechr == chr )
2700  return;
2701  if ( !zonechr->is_visible_to_me( chr ) )
2702  return;
2703  /* The two characters exist, and are in range of each other.
2704  Character 'chr''s lastx and lasty coordinates are valid.
2705  SO, if lastx/lasty are out of range of client->chr, we
2706  should send a 'create' type message. If they are in range,
2707  we should just send a move.
2708  */
2709  if ( chr->move_reason == Character::MULTIMOVE )
2710  {
2711  if ( client->ClientType & Network::CLIENTTYPE_7090 )
2712  {
2713  if ( chr->poisoned() ) // if poisoned send 0x17 for newer clients
2714  msgpoison.Send( client );
2715 
2716  if ( chr->invul() ) // if invul send 0x17 for newer clients
2717  msginvul.Send( client );
2718  return;
2719  }
2720  else
2721  {
2722 // NOTE: uncomment this line to make movement smoother (no stepping anims)
2723 // but basically makes it very difficult to talk while the ship
2724 // is moving.
2725 #ifdef PERGON
2726  send_remove_character( client, chr, msgremove );
2727 #else
2728 // send_remove_character( client, chr );
2729 #endif
2730  send_owncreate( client, chr, msgcreate.Get() );
2731  if ( chr->poisoned() )
2732  msgpoison.Send( client );
2733  if ( chr->invul() )
2734  msginvul.Send( client );
2735  }
2736  }
2737  else if ( Core::inrange( zonechr->x, zonechr->y, chr->lastx, chr->lasty ) )
2738  {
2739  msgmove.Send( client );
2740  if ( chr->poisoned() )
2741  msgpoison.Send( client );
2742  if ( chr->invul() )
2743  msginvul.Send( client );
2744  }
2745  else
2746  {
2747  send_owncreate( client, chr, msgcreate.Get() );
2748  if ( chr->poisoned() )
2749  msgpoison.Send( client );
2750  if ( chr->invul() )
2751  msginvul.Send( client );
2752  }
2753  } );
2754 
2755  // iter over all old in range players and send remove
2757  chr->lastx, chr->lasty, chr->realm, RANGE_VISUAL, [&]( Character* zonechr ) {
2758  Client* client = zonechr->client;
2759  if ( !zonechr->is_visible_to_me( chr ) )
2760  return;
2761 
2762  if ( Core::inrange( zonechr, chr ) ) // already handled
2763  return;
2764  // if we just walked out of range of this character, send its
2765  // client a remove object, or else a ghost character will remain.
2766  send_remove_character( client, chr, msgremove );
2767  } );
2768 }
2769 
2770 void Character::getpos_ifmove( Core::UFACING i_facing, unsigned short* px, unsigned short* py )
2771 {
2772  *px = x + Core::move_delta[i_facing].xmove;
2773  *py = y + Core::move_delta[i_facing].ymove;
2774 }
2775 
2777 {
2778  THREAD_CHECKPOINT( tasks, 800 );
2779  INFO_PRINT_TRACE( 20 ) << "swing_task_func(0x" << fmt::hexu( chr->serial ) << ")\n";
2781  chr->check_attack_after_move();
2782  THREAD_CHECKPOINT( tasks, 899 );
2783 }
2784 
2786 {
2787  INFO_PRINT_TRACE( 18 ) << "schedule_attack(0x" << fmt::hexu( this->serial ) << ")\n";
2788  // we'll get here with a swing_task already set, if
2789  // while in an adjacent cell to your opponent, you turn/move
2790  // while waiting for your timeout.
2791  if ( swing_task == nullptr )
2792  {
2793  unsigned int weapon_speed = weapon->speed();
2794  unsigned int weapon_delay = weapon->delay();
2795  Core::polclock_t clocks;
2796 
2797  if ( !weapon_delay )
2798  {
2799  INFO_PRINT_TRACE( 19 ) << "clocks[speed] = (" << Core::POLCLOCKS_PER_SEC << "*15000)/(("
2800  << dexterity() << "+100)*" << weapon_speed << ")\n";
2801 
2802  clocks = Core::POLCLOCKS_PER_SEC * static_cast<Core::polclock_t>( 15000L );
2803  clocks /= ( dexterity() + 100 ) * weapon_speed;
2804  }
2805  else
2806  {
2807  int delay_sum = weapon_delay + delay_mod();
2808  if ( delay_sum < 0 )
2809  delay_sum = 0;
2810 
2811  INFO_PRINT_TRACE( 19 ) << "clocks[delay] = ((" << weapon_delay << "+" << delay_mod() << "="
2812  << delay_sum << ")*" << Core::POLCLOCKS_PER_SEC << ")/1000\n";
2813 
2814  clocks = ( delay_sum * Core::POLCLOCKS_PER_SEC ) / 1000;
2815  }
2816 
2817  if ( clocks < ( Core::POLCLOCKS_PER_SEC / 5 ) )
2818  {
2819  INFO_PRINT_TRACE( 20 ) << name() << " attack timer: " << clocks << "\n";
2820  }
2821  INFO_PRINT_TRACE( 19 ) << "clocks=" << clocks << "\n";
2822 
2824  swing_task_func, this );
2825  }
2826 }
2827 
2829 {
2830  INFO_PRINT_TRACE( 15 ) << "reset_swing_timer(0x" << fmt::hexu( this->serial ) << ")\n";
2832 
2834  if ( swing_task )
2835  swing_task->cancel();
2836 
2837  if ( opponent_ || !opponent_of.empty() )
2838  {
2839  schedule_attack();
2840  }
2841 }
2842 
2844 {
2845  INFO_PRINT_TRACE( 15 ) << "manual_set_swing_timer(0x" << fmt::hexu( this->serial )
2846  << ") delay: " << clocks << "\n";
2848 
2850  if ( swing_task )
2851  swing_task->cancel();
2852 
2853  if ( opponent_ || !opponent_of.empty() )
2854  {
2856  swing_task_func, this );
2857  return true;
2858  }
2859  else
2860  return false;
2861 }
2862 
2863 /* The highlighted character is:
2864  Your selected_opponent, if you have one.
2865  If not, then the first char that has you as their opponent.
2866  Or, noone.
2867  */
2869 {
2870  if ( opponent_ != nullptr )
2871  return opponent_;
2872  else if ( !opponent_of.empty() )
2873  return *opponent_of.begin();
2874  else
2875  return nullptr;
2876 }
2877 
2879 {
2880  passert( who != nullptr );
2881  if ( Core::settingsManager.combat_config.scripted_attack_checks )
2882  {
2883  INFO_PRINT_TRACE( 21 ) << "is_attackable(0x" << fmt::hexu( this->serial ) << ",0x"
2884  << fmt::hexu( who->serial ) << "): will be handled by combat hook.\n";
2885  return true;
2886  }
2887  else
2888  {
2889  INFO_PRINT_TRACE( 21 ) << "is_attackable(0x" << fmt::hexu( this->serial ) << ",0x"
2890  << fmt::hexu( who->serial ) << "):\n"
2891  << " who->dead: " << who->dead() << "\n"
2892  << " wpn->inrange: " << weapon->in_range( this, who ) << "\n"
2893  << " hidden: " << hidden() << "\n"
2894  << " who->hidden: " << who->hidden() << "\n"
2895  << " concealed: " << is_concealed_from_me( who ) << "\n";
2896  if ( who->dead() )
2897  return false;
2898  else if ( !weapon->in_range( this, who ) )
2899  return false;
2901  return false;
2902  else if ( who->hidden() && !cached_settings.get( PRIV_FLAGS::ATTACK_HIDDEN ) )
2903  return false;
2904  else if ( is_concealed_from_me( who ) )
2905  return false;
2906  else if ( !realm->has_los( *this, *who ) )
2907  return false;
2908  else
2909  return true;
2910  }
2911 }
2912 
2914 {
2915  if ( opponent_ != nullptr )
2916  {
2917  INFO_PRINT_TRACE( 20 ) << "get_attackable_opponent(0x" << fmt::hexu( this->serial )
2918  << "): checking opponent, 0x" << fmt::hexu( opponent_->serial ) << "\n";
2919  if ( is_attackable( opponent_ ) )
2920  return opponent_;
2921  }
2922 
2923  if ( !opponent_of.empty() )
2924  {
2925  for ( auto& who : opponent_of )
2926  {
2927  INFO_PRINT_TRACE( 20 ) << "get_attackable_opponent(0x" << fmt::hexu( this->serial )
2928  << "): checking opponent_of, 0x" << fmt::hexu( who->serial ) << "\n";
2929  if ( is_attackable( who ) )
2930  return who;
2931  }
2932  }
2933 
2934  return nullptr;
2935 }
2936 
2938 {
2939  if ( client != nullptr && has_active_client() )
2940  {
2941  Character* opponent = get_opponent();
2942 
2944  if ( opponent != nullptr )
2945  msg->Write<u32>( opponent->serial_ext );
2946  else
2947  msg->offset += 4;
2948  msg.Send( client );
2949  }
2950 }
2951 
2953 {
2954  // do nothing
2955 }
2956 
2958 {
2959  // someone has just disengaged. If we don't have an explicit opponent,
2960  // pick one of those that has us targetted as the highlight character.
2961  if ( opponent_ == nullptr )
2962  send_highlight();
2963 }
2964 
2966 {
2967  // someone has targetted us. If we don't have an explicit opponent,
2968  // pick one of those that has us targetted as the highlight character.
2969  if ( opponent_ == nullptr )
2970  send_highlight();
2971 }
2972 
2974 {
2975  // virtual that does nothing at character level, but fires event for NPCs
2976 }
2977 
2979 {
2980  // virtual that does nothing at character level, but fires event for NPCs
2981 }
2982 
2984 {
2985  // virtual that does nothing at character level, but fires event for NPCs
2986 }
2987 
2989 {
2990  // consider moving PropagateMove here!
2991 }
2993 
2994 void Character::set_opponent( Character* new_opponent, bool inform_old_opponent )
2995 {
2996  INFO_PRINT_TRACE( 12 ) << "set_opponent(0x" << fmt::hexu( this->serial ) << ",0x"
2997  << fmt::hex( new_opponent->serial ) << ")\n";
2998  if ( new_opponent != nullptr )
2999  {
3000  if ( new_opponent->dead() )
3001  return;
3002 
3003  if ( !warmode() && ( script_isa( Core::POLCLASS_NPC ) || has_active_client() ) )
3004  set_warmode( true );
3005  }
3006 
3007  if ( opponent_ != nullptr )
3008  {
3009  opponent_->opponent_of.erase( this );
3010  // Turley 05/26/09 no need to send disengaged event on shutdown
3011  if ( !Clib::exit_signalled )
3012  {
3013  if ( inform_old_opponent && opponent_ != nullptr )
3014  opponent_->inform_disengaged( this );
3015  }
3016  }
3017 
3018  opponent_ = new_opponent;
3019 
3020 
3021  // Turley 05/26/09 possible shutdown crashfix during cleanup
3022  // (inside schedule_attack() the rest is also senseless on shutdowncleanup)
3023  if ( !Clib::exit_signalled )
3024  {
3026 
3027  if ( opponent_ != nullptr )
3028  {
3030  if ( opponent_->get_opponent() == nullptr )
3032 
3033  opponent_->opponent_of.insert( this );
3034 
3035  opponent_->inform_engaged( this );
3036 
3038  }
3039 
3040  send_highlight();
3041  }
3042 }
3043 
3045 {
3046  // test for setting to same so swing timer doesn't reset
3047  // if you double-click the same guy over and over
3048  if ( opponent_ == nullptr || opponent_->serial != opp_serial )
3049  {
3050  Character* new_opponent = Core::find_character( opp_serial );
3051  if ( new_opponent != nullptr )
3052  {
3053  if ( realm != new_opponent->realm )
3054  return;
3055  set_opponent( new_opponent );
3056  }
3057  }
3058 }
3059 
3061 {
3062  time_t new_disable_time = Core::poltime() + seconds;
3063  if ( new_disable_time > disable_regeneration_until )
3064  disable_regeneration_until = new_disable_time;
3065 }
3066 
3068 {
3069  return mob_flags_.get( MOB_FLAGS::WARMODE );
3070 }
3071 
3072 void Character::set_warmode( bool i_warmode )
3073 {
3074  if ( Core::gamestate.system_hooks.warmode_change )
3076  new Bscript::BLong( i_warmode ) );
3077 
3078  if ( warmode() != i_warmode )
3079  {
3081  }
3082 
3083  mob_flags_.change( MOB_FLAGS::WARMODE, i_warmode );
3084  if ( i_warmode == false )
3085  {
3086  set_opponent( nullptr );
3087  }
3089 
3090  if ( dead() )
3091  {
3092  if ( warmode() ) // if entered warmode, display me now
3093  {
3095  }
3096  else // if leaving warmode, I go invisible.
3097  {
3099  }
3100  }
3101  else
3102  {
3103  Network::MoveChrPkt msgmove( this );
3105  if ( chr == this )
3106  return;
3107  msgmove.Send( chr->client );
3108  } );
3109  }
3110 }
3111 
3113 {
3114  return attribute( weapon->attribute().attrid );
3115 }
3116 
3117 unsigned short Character::random_weapon_damage() const
3118 {
3119  return weapon->get_random_damage();
3120 }
3121 
3122 unsigned short Character::min_weapon_damage() const
3123 {
3124  return weapon->descriptor().damage_dice.min_value() + weapon->damage_mod();
3125 }
3126 
3127 unsigned short Character::max_weapon_damage() const
3128 {
3129  return weapon->descriptor().damage_dice.max_value() + weapon->damage_mod();
3130 }
3131 
3133 {
3134  if ( !weapon->is_intrinsic() && !weapon->is_projectile() )
3135  {
3137  }
3138 }
3139 
3141 {
3142  double f = Clib::random_double( Core::gamestate.armor_zone_chance_sum );
3143  for ( unsigned zone = 0; zone < Core::gamestate.armorzones.size(); ++zone )
3144  {
3145  f -= Core::gamestate.armorzones[zone].chance;
3146  if ( f <= 0.0 )
3147  {
3148  return armor_[zone];
3149  }
3150  }
3151  return nullptr;
3152 }
3153 
3155 {
3156  if ( on_mount() )
3157  return weapon->mounted_anim();
3158  else
3159  return weapon->anim();
3160 }
3161 
3163 {
3164  if ( weapon->is_projectile() )
3165  {
3166  // 234 is hit, 238 is miss??
3168  play_moving_effect( this, target, weapon->projectile_anim(),
3169  9, // Speed (??)
3170  0, // Loop
3171  0 ); // Explode
3172  if ( graphic >= UOBJ_HUMAN_MALE )
3173  {
3175  }
3176  else
3177  {
3179  }
3180  }
3181  else if ( graphic >= UOBJ_HUMAN_MALE )
3182  {
3184  }
3185  else
3186  {
3188  }
3189 }
3190 
3192 {
3193  unsigned short sound = weapon->hit_sound();
3194  if ( sound )
3195  play_sound_effect( this, sound );
3196 }
3197 
3199 {
3200  unsigned short sound = weapon->miss_sound();
3201  if ( sound )
3202  play_sound_effect( this, sound );
3203 }
3204 
3206 {
3207  if ( gender == Core::GENDER_MALE )
3210 }
3211 
3213 {
3214  if ( Core::settingsManager.combat_config.core_hit_sounds )
3215  {
3217  }
3218  if ( objtype_ >= UOBJ_HUMAN_MALE )
3220 }
3221 
3222 
3223 void Character::attack( Character* opponent )
3224 {
3225  INC_PROFILEVAR( combat_operations );
3226 
3227  if ( Core::gamestate.system_hooks.attack_hook )
3228  {
3229  if ( Core::gamestate.system_hooks.attack_hook->call(
3230  new Module::ECharacterRefObjImp( this ),
3231  new Module::ECharacterRefObjImp( opponent ) ) )
3232  return;
3233  }
3234 
3235  if ( Core::settingsManager.watch.combat )
3236  INFO_PRINT << name() << " attacks " << opponent->name() << "\n";
3237 
3238  if ( weapon->is_projectile() )
3239  {
3240  Core::UContainer* bp = backpack();
3241  if ( Core::gamestate.system_hooks.consume_ammunition_hook )
3242  {
3243  if ( Core::gamestate.system_hooks.consume_ammunition_hook->call(
3245  false )
3246  {
3247  return;
3248  }
3249  }
3250  else if ( ( bp == nullptr ) || ( weapon->consume_projectile( bp ) == false ) )
3251  {
3252  // 04/2007 - MuadDib
3253  // Range through wornitems to find containers and check
3254  // here also if backpack fails. Use the mainpack first this way.
3255  bool projectile_check = false;
3256  for ( unsigned layer = Core::LAYER_EQUIP__LOWEST; layer <= Core::LAYER_EQUIP__HIGHEST;
3257  layer++ )
3258  {
3259  Items::Item* item = wornitems->GetItemOnLayer( layer );
3260  if ( item )
3261  {
3262  if ( item != nullptr && item->script_isa( Core::POLCLASS_CONTAINER ) )
3263  {
3264  if ( layer != Core::LAYER_HAIR && layer != Core::LAYER_FACE &&
3265  layer != Core::LAYER_BEARD && layer != Core::LAYER_BACKPACK &&
3266  layer != Core::LAYER_MOUNT )
3267  {
3268  Core::UContainer* cont = static_cast<Core::UContainer*>( item );
3269 
3270  if ( weapon->consume_projectile( cont ) == true )
3271  {
3272  projectile_check = true;
3273  break;
3274  }
3275  }
3276  }
3277  }
3278  }
3279  // I'm out of projectiles.
3280  if ( projectile_check == false )
3281  return;
3282  }
3283  }
3284 
3285  repsys_on_attack( opponent );
3286  repsys_on_damage( opponent );
3287 
3288  do_attack_effects( opponent );
3289 
3290  if ( Core::gamestate.system_hooks.combat_advancement_hook )
3291  {
3294  new Module::ECharacterRefObjImp( opponent ) );
3295  }
3296 
3297  double hit_chance = ( weapon_attribute().effective() + 50.0 ) /
3298  ( 2.0 * ( opponent->weapon_attribute().effective() + 50.0 ) );
3299  hit_chance += hitchance_mod() * 0.001f;
3300  hit_chance -= opponent->evasionchance_mod() * 0.001f;
3301  if ( Core::settingsManager.watch.combat )
3302  INFO_PRINT << "Chance to hit: " << hit_chance << ": ";
3303  if ( Clib::random_double( 1.0 ) < hit_chance )
3304  {
3305  if ( Core::settingsManager.watch.combat )
3306  INFO_PRINT << "Hit!\n";
3308 
3309  double damage = random_weapon_damage();
3310  damage_weapon();
3311 
3312  if ( Core::settingsManager.watch.combat )
3313  INFO_PRINT << "Base damage: " << damage << "\n";
3314 
3315  double damage_multiplier = attribute( Core::gamestate.pAttrTactics->attrid ).effective() + 50;
3316  damage_multiplier += strength() * 0.20f;
3317  damage_multiplier *= 0.01f;
3318 
3319  damage *= damage_multiplier;
3320 
3321  if ( Core::settingsManager.watch.combat )
3322  INFO_PRINT << "Damage multiplier due to tactics/STR: " << damage_multiplier
3323  << " Result: " << damage << "\n";
3324 
3325  if ( opponent->shield != nullptr )
3326  {
3327  if ( Core::gamestate.system_hooks.parry_advancement_hook )
3328  {
3331  new Module::ECharacterRefObjImp( opponent ),
3332  new Module::EItemRefObjImp( opponent->shield ) );
3333  }
3334 
3335  double parry_chance =
3336  opponent->attribute( Core::gamestate.pAttrParry->attrid ).effective() / 200.0;
3337  if ( Core::settingsManager.watch.combat )
3338  INFO_PRINT << "Parry Chance: " << parry_chance << ": ";
3339  if ( Clib::random_double( 1.0 ) < parry_chance )
3340  {
3341  if ( Core::settingsManager.watch.combat )
3342  INFO_PRINT << opponent->shield->ar() << " hits deflected\n";
3343  if ( Core::settingsManager.combat_config.display_parry_success_messages &&
3344  opponent->client )
3345  Core::send_sysmessage( opponent->client, "You successfully parried the attack!" );
3346 
3347  damage -= opponent->shield->ar();
3348  if ( damage < 0 )
3349  damage = 0;
3350  }
3351  else
3352  {
3353  if ( Core::settingsManager.watch.combat )
3354  INFO_PRINT << "failed.\n";
3355  }
3356  }
3357  if ( weapon->hit_script().empty() )
3358  {
3359  opponent->apply_damage( damage, this, true,
3360  Core::settingsManager.combat_config.send_damage_packet );
3361  }
3362  else
3363  {
3364  run_hit_script( opponent, damage );
3365  }
3366  }
3367  else
3368  {
3369  if ( Core::settingsManager.watch.combat )
3370  INFO_PRINT << "Miss!\n";
3371  opponent->on_swing_failure( this );
3373  if ( Core::gamestate.system_hooks.hitmiss_hook )
3374  {
3376  new Module::ECharacterRefObjImp( this ), new Module::ECharacterRefObjImp( opponent ) );
3377  }
3378  }
3379 }
3380 
3382 {
3384  Character* opponent = get_attackable_opponent();
3386  INFO_PRINT_TRACE( 20 ) << "check_attack_after_move(0x" << fmt::hexu( this->serial )
3387  << "): opponent is 0x" << fmt::hexu( opponent->serial ) << "\n";
3388  if ( opponent != nullptr && // and I have an opponent
3389  !dead() && // If I'm not dead
3390  ( Core::settingsManager.combat_config.attack_while_frozen ||
3391  ( !paralyzed() && !frozen() ) ) )
3392  {
3394  if ( mob_flags_.get( MOB_FLAGS::READY_TO_SWING ) ) // and I can swing now,
3395  { // do so.
3397  if ( Core::settingsManager.combat_config.send_swing_packet && client != nullptr )
3398  send_fight_occuring( client, opponent );
3399  attack( opponent );
3403  }
3404  else
3405  {
3407  INFO_PRINT_TRACE( 20 ) << "not ready to swing\n";
3408  schedule_attack();
3410  }
3411  }
3413 }
3414 
3415 
3417 {
3418  auto light_unil = lightoverride_until();
3419  if ( light_unil < Core::read_gameclock() && light_unil != ~0u )
3420  {
3421  lightoverride_until( 0 );
3422  lightoverride( -1 );
3423  }
3425  !has_lightoverride() )
3426  return;
3427 
3428  int newlightlevel;
3429  if ( has_lightoverride() )
3430  newlightlevel = lightoverride();
3431  else
3432  {
3433  // dave 12-22 check for no regions
3435  if ( light_region != nullptr )
3436  newlightlevel = light_region->lightlevel;
3437  else
3439  }
3440 
3441  if ( newlightlevel != client->gd->lightlevel )
3442  {
3443  Core::send_light( client, newlightlevel );
3444  client->gd->lightlevel = newlightlevel;
3445  }
3446 }
3447 
3449 {
3450  Core::JusticeRegion* cur_justice_region = client->gd->justice_region;
3451  Core::JusticeRegion* new_justice_region =
3453 
3454  if ( cur_justice_region != new_justice_region )
3455  {
3456  if ( cur_justice_region != nullptr )
3457  cur_justice_region->RunLeaveScript( client->chr );
3458  if ( new_justice_region != nullptr )
3459  new_justice_region->RunEnterScript( client->chr );
3460 
3461  // print 'leaving' message
3462  bool printmsgs;
3463  if ( cur_justice_region != nullptr && new_justice_region != nullptr &&
3464  cur_justice_region->entertext() == new_justice_region->entertext() &&
3465  cur_justice_region->leavetext() == new_justice_region->leavetext() )
3466  {
3467  printmsgs = false;
3468  }
3469  else
3470  {
3471  printmsgs = true;
3472  }
3473 
3474  if ( printmsgs && cur_justice_region )
3475  {
3476  const std::string& leavetext = cur_justice_region->leavetext();
3477  if ( !leavetext.empty() )
3478  {
3479  Core::send_sysmessage( client, leavetext );
3480  }
3481  }
3482 
3483  client->gd->justice_region = new_justice_region;
3484 
3485  if ( new_justice_region && new_justice_region->RunNoCombatCheck( client ) == true )
3486  {
3487  Character* opp2 = get_opponent();
3488  if ( ( opp2 != nullptr && opp2->client ) )
3489  {
3490  opp2->opponent_of.erase( client->chr );
3491  opp2->set_opponent( nullptr, true );
3492  opp2->schedule_attack();
3493  opp2->opponent_ = nullptr;
3494  opp2->clear_opponent_of();
3495  set_opponent( nullptr, true );
3496  if ( swing_task != nullptr )
3497  swing_task->cancel();
3498  }
3499  }
3500 
3501 
3502  // print 'entering' message
3503  // handle nocombat while we have entered.
3504  if ( printmsgs && new_justice_region )
3505  {
3506  const std::string& entertext = new_justice_region->entertext();
3507  if ( !entertext.empty() )
3508  {
3509  Core::send_sysmessage( client, entertext );
3510  }
3511  }
3512  }
3513 }
3514 
3516 {
3517  Core::MusicRegion* cur_music_region = client->gd->music_region;
3518  Core::MusicRegion* new_music_region = Core::gamestate.musicdef->getregion( x, y, realm );
3519 
3520  // may want to consider changing every n minutes, too, even if region didn't change
3521  if ( cur_music_region != new_music_region )
3522  {
3523  client->gd->music_region = new_music_region;
3524  if ( new_music_region != nullptr )
3525  {
3526  Core::send_midi( client, new_music_region->getmidi() );
3527  }
3528  else
3529  {
3530  Core::send_midi( client, 0 );
3531  }
3532  }
3533 }
3534 
3535 void Character::check_weather_region_change( bool force ) // dave changed 5/26/03 - use force
3536  // boolean if current weather region
3537  // changed type/intensity
3538 {
3539  Core::WeatherRegion* cur_weather_region = client->gd->weather_region;
3540  Core::WeatherRegion* new_weather_region = Core::gamestate.weatherdef->getregion( x, y, realm );
3541 
3542  // eric 5/31/03: I don't think this is right. it's possible to go from somewhere that has no
3543  // weather region,
3544  // and to walk to somewhere that doesn't have a weather region.
3545  //
3546  if ( force || ( cur_weather_region != new_weather_region ) )
3547  {
3548  if ( new_weather_region != nullptr && new_weather_region->lightoverride != -1 &&
3549  !has_lightoverride() )
3550  {
3551  Core::send_light( client, new_weather_region->lightoverride );
3552  client->gd->lightlevel = new_weather_region->lightoverride;
3553  }
3554 
3555  // eric removed this 5/31/03, it's calling itself recursively:
3556  // move_character_to -> tellmove -> check_region_changes -> check_weather_region_change (here,
3557  // doh)
3558  // if you need to send the client something special, just do it.
3559  // move_character_to(this,x,y,z,0); //dave added 5/26/03: client doesn't refresh properly
3560  // without a teleport :| and send_goxyz causes weather effects to stop if character is
3561  // walking/running too
3562 
3563  if ( new_weather_region )
3564  {
3565  Core::send_weather( client, new_weather_region->weathertype, new_weather_region->severity,
3566  new_weather_region->aux );
3567  }
3568  else
3569  {
3570  Core::send_weather( client, 0xff, 0, 0 ); // turn off
3571  }
3572  client->gd->weather_region = new_weather_region;
3573  }
3574 }
3575 
3577 {
3578  if ( client != nullptr )
3579  {
3581 
3583 
3585 
3587  }
3588 }
3589 
3591 {
3592  wornitems->x = x;
3593  wornitems->y = y;
3594  wornitems->z = z;
3595  wornitems->realm = realm;
3596 }
3597 
3599 {
3600  if ( Core::gamestate.system_hooks.un_hide != nullptr )
3601  {
3602  if ( !Core::gamestate.system_hooks.un_hide->call( make_mobileref( this ) ) )
3603  return;
3604  }
3605 
3606  hidden( false );
3607  if ( is_visible() )
3608  {
3609  if ( client != nullptr )
3610  send_owncreate( client, this );
3611 
3613  if ( chr == this )
3614  return;
3615  if ( !chr->is_visible_to_me( this ) )
3616  return;
3617  send_owncreate( chr->client, this );
3618  } );
3619 
3620  realm->notify_unhid( *this );
3621  }
3622 }
3623 
3624 void Character::set_stealthsteps( unsigned short newval )
3625 {
3626  stealthsteps_ = newval;
3627 }
3628 
3630 {
3636 }
3637 
3638 /*
3639  This isn't quite right, for hidden characters.
3640  What normally happens:
3641  1) Client sends "use skill hiding"
3642  2) Server sends "77 move" with the hidden flag set.
3643  3) client sends move-request
3644  4) server sends move-approve
3645  5) server sense "78 create" message with hidden flag clear, at new posn.
3646 
3647  We're sending the "78 create" _before_ the move-approve.
3648  */
3649 
3651 {
3652  if ( can_freemove() )
3653  return true;
3654 
3655  if ( frozen() || paralyzed() )
3656  {
3657  if ( client != nullptr )
3658  {
3659  if ( frozen() )
3660  private_say_above( this, this, "I am frozen and cannot move." );
3661  else if ( paralyzed() )
3662  private_say_above( this, this, "I am paralyzed and cannot move." );
3663  }
3664  return false;
3665  }
3666 
3667  if ( Core::settingsManager.ssopt.movement_uses_stamina &&
3668  vital( Core::gamestate.pVitalStamina->vitalid ).current_ones() == 0 && !dead() )
3669  {
3670  private_say_above( this, this, "You are too fatigued to move." );
3671  return false;
3672  }
3673 
3674  return true;
3675 }
3676 
3677 
3678 bool Character::face( Core::UFACING i_facing, int flags )
3679 {
3680  if ( ( flags & 1 ) == 0 )
3681  {
3682  if ( !can_face( i_facing ) )
3683  return false;
3684  }
3685 
3686  if ( i_facing != facing )
3687  {
3688  setfacing( static_cast<u8>( i_facing ) );
3689 
3690  if ( Core::settingsManager.combat_config.reset_swing_onturn &&
3694  {
3695  if ( stealthsteps_ == 0 )
3696  unhide();
3697  else
3698  stealthsteps_--;
3699  }
3700  }
3701 
3702  return true;
3703 }
3704 
3705 
3706 bool Character::CustomHousingMove( unsigned char i_dir )
3707 {
3708  passert( facing < 8 );
3709 
3711  if ( multi != nullptr )
3712  {
3713  Multi::UHouse* house = multi->as_house();
3714  if ( house != nullptr )
3715  {
3716  Core::UFACING i_facing = static_cast<Core::UFACING>( i_dir & PKTIN_02_FACING_MASK );
3717  if ( i_facing != facing )
3718  {
3719  setfacing( static_cast<u8>( i_facing ) );
3720  set_dirty();
3721  dir = i_dir;
3722  return true;
3723  }
3724  else
3725  {
3726  s8 newz = house->z +
3728  u16 newx = x + Core::move_delta[facing].xmove;
3729  u16 newy = y + Core::move_delta[facing].ymove;
3730  const Multi::MultiDef& def = house->multidef();
3731  if ( newx > ( house->x + def.minrx ) && newx <= ( house->x + def.maxrx ) &&
3732  newy > ( house->y + def.minry ) && newy <= ( house->y + def.maxry ) )
3733  {
3734  x = static_cast<u16>( newx );
3735  y = static_cast<u16>( newy );
3736  z = static_cast<s8>( newz );
3737  MoveCharacterWorldPosition( lastx, lasty, x, y, this, nullptr );
3738 
3739  position_changed();
3740  set_dirty();
3741  return true;
3742  }
3743  }
3744  }
3745  }
3746  return false;
3747 }
3748 
3749 //************************************
3750 // Method: move
3751 // FullName: Character::move
3752 // Access: public
3753 // Returns: bool
3754 // Qualifier:
3755 // Parameter: unsigned char i_dir
3756 //************************************
3757 bool Character::move( unsigned char i_dir )
3758 {
3759  lastx = x;
3760  lasty = y;
3761  lastz = z;
3762 
3763  // if currently building a house chr can move free inside the multi
3764  if ( is_house_editing() )
3765  return CustomHousingMove( i_dir );
3766 
3767  u8 oldFacing = facing;
3768 
3769  Core::UFACING i_facing = static_cast<Core::UFACING>( i_dir & PKTIN_02_FACING_MASK );
3770  if ( !face( i_facing ) )
3771  return false;
3772 
3773  // If we're a player, and we used our "move" command to turn,
3774  // we want to skip the meat of this function
3775  if ( ( script_isa( Core::POLCLASS_NPC ) ) || ( facing == oldFacing ) )
3776  {
3777  if ( facing & 1 ) // check if diagonal movement is allowed -- Nando (2009-02-26)
3778  {
3779  short new_z;
3780  u8 tmp_facing = ( facing + 1 ) & 0x7;
3781  unsigned short tmp_newx = x + Core::move_delta[tmp_facing].xmove;
3782  unsigned short tmp_newy = y + Core::move_delta[tmp_facing].ymove;
3783 
3784  // needs to save because if only one direction is blocked, it shouldn't block ;)
3785  bool walk1 =
3786  realm->walkheight( this, tmp_newx, tmp_newy, z, &new_z, nullptr, nullptr, nullptr );
3787 
3788  tmp_facing = ( facing - 1 ) & 0x7;
3789  tmp_newx = x + Core::move_delta[tmp_facing].xmove;
3790  tmp_newy = y + Core::move_delta[tmp_facing].ymove;
3791 
3792  if ( !walk1 &&
3793  !realm->walkheight( this, tmp_newx, tmp_newy, z, &new_z, nullptr, nullptr, nullptr ) )
3794  return false;
3795  }
3796 
3797  unsigned short newx = x + Core::move_delta[facing].xmove;
3798  unsigned short newy = y + Core::move_delta[facing].ymove;
3799 
3800  // FIXME consider consolidating with similar code in UOEMOD.CPP
3801  short newz;
3802  Multi::UMulti* supporting_multi;
3803  Items::Item* walkon_item;
3804 
3805  short current_boost = gradual_boost;
3806  if ( !realm->walkheight( this, newx, newy, z, &newz, &supporting_multi, &walkon_item,
3807  &current_boost ) )
3808  return false;
3809 
3810  remote_containers_.clear();
3811 
3812  if ( !CheckPushthrough() )
3813  return false;
3814 
3815  if ( !can_freemove() && Core::settingsManager.ssopt.movement_uses_stamina && !dead() )
3816  {
3817  int carry_perc = weight() * 100 / carrying_capacity();
3818  unsigned short tmv = movecost(
3819  this, carry_perc, ( i_dir & PKTIN_02_DIR_RUNNING_BIT ) ? true : false, on_mount() );
3820  VitalValue& stamina = vital( Core::gamestate.pVitalStamina->vitalid );
3821  // u16 old_stamina = stamina.current_ones();
3822  if ( !consume( Core::gamestate.pVitalStamina, stamina, tmv ) )
3823  {
3824  private_say_above( this, this, "You are too fatigued to move." );
3825  return false;
3826  }
3827  }
3828 
3829  // Maybe have a flag for this in servspecopt?
3832 
3833  x = static_cast<u16>( newx );
3834  y = static_cast<u16>( newy );
3835  z = static_cast<s8>( newz );
3836 
3837  if ( on_mount() && !script_isa( Core::POLCLASS_NPC ) )
3838  {
3839  mountedsteps_++;
3840  }
3841  // FIXME: Need to add Walkon checks for multi right here if type is house.
3842  if ( supporting_multi != nullptr )
3843  {
3844  supporting_multi->register_object( this );
3845  Multi::UHouse* this_house = supporting_multi->as_house();
3846  if ( this->registered_house == 0 )
3847  {
3848  this->registered_house = supporting_multi->serial;
3849 
3850  if ( this_house != nullptr )
3851  this_house->walk_on( this );
3852  }
3853  }
3854  else
3855  {
3856  if ( registered_house > 0 )
3857  {
3859  if ( multi != nullptr )
3860  {
3861  multi->unregister_object( (UObject*)this );
3862  }
3863  registered_house = 0;
3864  }
3865  }
3866 
3867  gradual_boost = current_boost;
3868  MoveCharacterWorldPosition( lastx, lasty, x, y, this, nullptr );
3869 
3870  position_changed();
3871  if ( walkon_item != nullptr )
3872  {
3873  walkon_item->walk_on( this );
3874  }
3875 
3876  if ( hidden() )
3877  {
3878  if ( ( ( i_dir & PKTIN_02_DIR_RUNNING_BIT ) &&
3880  ( stealthsteps_ == 0 ) )
3881  unhide();
3882  else if ( stealthsteps_ )
3883  --stealthsteps_;
3884  }
3885 
3886  if ( Core::gamestate.system_hooks.ouch_hook != nullptr )
3887  {
3888  if ( ( lastz - z ) > 21 )
3889  Core::gamestate.system_hooks.ouch_hook->call(
3890  make_mobileref( this ), new Bscript::BLong( lastx ), new Bscript::BLong( lasty ),
3891  new Bscript::BLong( lastz ) );
3892  }
3893  }
3894 
3895  set_dirty();
3896  dir = i_dir;
3897 
3898  return true;
3899 
3900 
3901  // this would be a great place for tellmove(), except that
3902  // we want to send the move acknowledge to the client before
3903  // sending the move/create messages to the neighboring clients.
3904 
3905  // Why? Maybe to give the best response time to the client.
3906 
3907  // may want to rethink this, since it's starting to complicate
3908  // things.
3909 }
3910 
3912 {
3913  // Commented out the explicit backpack handling, should be handled
3914  // automagically by wormitems realm handling. There is a slim
3915  // possibility that backpacks might be assigned to a character but
3916  // not be a worn item? If this is the case, that will be broken.
3917  // backpack()->realm = realm;
3918  // backpack()->for_each_item(setrealm, (void*)realm);
3919  wornitems->for_each_item( Core::setrealm, (void*)realm );
3920  if ( has_gotten_item() )
3921  gotten_item()->realm = realm;
3922  if ( trading_cont.get() )
3923  trading_cont->realm = realm;
3924 
3925  if ( has_active_client() )
3926  {
3927  // these are important to keep here in this order
3930  if ( Core::settingsManager.ssopt.core_sends_season )
3934  }
3935 }
3936 
3938 {
3939  if ( !can_freemove() && Core::gamestate.system_hooks.pushthrough_hook != nullptr )
3940  {
3941  unsigned short newx = x + Core::move_delta[facing].xmove;
3942  unsigned short newy = y + Core::move_delta[facing].ymove;
3943  auto mobs = std::unique_ptr<Bscript::ObjArray>();
3944 
3946  newx, newy, realm, 0, [&]( Mobile::Character* _chr ) {
3947  if ( _chr->z >= z - 10 && _chr->z <= z + 10 && !_chr->dead() &&
3948  ( is_visible_to_me( _chr ) ||
3949  _chr->hidden() ) ) // add hidden mobs even if they're not visible to me
3950  {
3951  if ( !mobs )
3952  mobs.reset( new Bscript::ObjArray );
3953  mobs->addElement( make_mobileref( _chr ) );
3954  }
3955  } );
3956 
3957  if ( mobs )
3958  {
3960  mobs.release() );
3961  }
3962  return true;
3963  }
3964  return true;
3965 }
3966 
3968 {
3970  PropagateMove( this );
3971 
3972  // notify npcs and items (maybe the PropagateMove should also go there eventually? - Nando
3973  // 2018-06-16)
3974  realm->notify_moved( *this );
3975 
3977 
3978  if ( opponent_ != nullptr )
3980 
3981  // attacking can change the opponent_of array drastically.
3982  std::set<Character*> tmp( opponent_of );
3983  for ( auto& chr : tmp )
3984  {
3985  chr->check_attack_after_move();
3986  }
3987 
3988  move_reason = OTHER;
3989 }
3990 
3992 {
3993  remote_containers_.push_back( Core::ItemRef( item ) );
3994 }
3995 
3996 Items::Item* Character::search_remote_containers( u32 find_serial, bool* isRemoteContainer ) const
3997 {
3998  if ( isRemoteContainer )
3999  *isRemoteContainer = false;
4000  for ( const auto& elem : remote_containers_ )
4001  {
4002  Items::Item* item = elem.get();
4003  if ( item->orphan() )
4004  continue; // it'll be cleaned up when they move
4005  if ( item->serial == find_serial )
4006  {
4007  if ( isRemoteContainer )
4008  *isRemoteContainer = true;
4009  return item;
4010  }
4011  if ( item->isa( Core::UOBJ_CLASS::CLASS_CONTAINER ) )
4012  {
4013  item = ( (Core::UContainer*)item )->find( find_serial );
4014  if ( item )
4015  {
4016  if ( isRemoteContainer )
4017  *isRemoteContainer = false;
4018  return item;
4019  }
4020  }
4021  }
4022  return nullptr;
4023 }
4024 
4025 bool Character::mightsee( const Items::Item* item ) const
4026 {
4027  while ( item->container != nullptr )
4028  item = item->container;
4029 
4030  for ( const auto& elem : remote_containers_ )
4031  {
4032  Items::Item* additional_item = elem.get();
4033  if ( additional_item == item )
4034  return true;
4035  }
4036 
4037 
4038  return ( ( item->realm == realm ) && ( abs( x - item->x ) <= RANGE_VISUAL ) &&
4039  ( abs( y - item->y ) <= RANGE_VISUAL ) );
4040 }
4041 
4043 {
4044  Core::gameclock_t squelched = squelched_until();
4045  if ( squelched == 0 )
4046  return false;
4047  else if ( squelched == ~0u )
4048  return true;
4049 
4050  if ( Core::read_gameclock() < squelched )
4051  {
4052  return true;
4053  }
4054  else
4055  {
4056  const_cast<Character*>( this )->squelched_until( 0 );
4057  return false;
4058  }
4059 }
4060 
4062 {
4063  Core::gameclock_t deafened = deafened_until();
4064  if ( deafened == 0 )
4065  return false;
4066  else if ( deafened == ~0u )
4067  return true;
4068 
4069  if ( Core::read_gameclock() < deafened )
4070  {
4071  return true;
4072  }
4073  else
4074  {
4075  const_cast<Character*>( this )->deafened_until( 0 );
4076  return false;
4077  }
4078 }
4079 
4080 bool Character::invul() const
4081 {
4083 }
4084 
4086 {
4087  return static_cast<u16>( attribute( Core::gamestate.pAttrStrength->attrid ).effective() );
4088 }
4090 {
4091  return static_cast<u16>( attribute( Core::gamestate.pAttrDexterity->attrid ).effective() );
4092 }
4094 {
4095  return static_cast<u16>( attribute( Core::gamestate.pAttrIntelligence->attrid ).effective() );
4096 }
4097 
4099 {
4100  if ( tcursor2 != nullptr )
4101  return true;
4102  if ( client && client->gd && client->gd->target_cursor_uoemod != nullptr )
4103  return true;
4104  return false;
4105 }
4106 
4107 // get_legal_item removed, wasn't being used. - MuadDib
4108 
4110 {
4111  menu.clear();
4112  if ( on_menu_selection != nullptr )
4113  on_menu_selection( client, nullptr, nullptr );
4114  on_menu_selection = nullptr;
4115 }
4116 
4118 {
4119  return ( trading_with.get() != nullptr );
4120 }
4121 
4123 {
4125 }
4126 
4127 void Character::trade_accepted( bool newvalue )
4128 {
4130 }
4131 
4133 {
4134  if ( trading_cont.get() == nullptr ) // FIXME hardcoded
4135  {
4136  Items::Item* cont = Items::Item::create( Core::settingsManager.extobj.secure_trade_container );
4137  cont->realm = realm;
4138  trading_cont.set( static_cast<Core::UContainer*>( cont ) );
4139  }
4140 }
4141 
4143 {
4144  return trading_cont.get();
4145 }
4146 
4147 // SkillValue removed for no use - MuadDib
4148 
4149 const char* Character::target_tag() const
4150 {
4151  return "mobile";
4152 }
4153 
4155 {
4156  for ( unsigned ai = 0; ai < Core::gamestate.numAttributes; ++ai )
4157  {
4158  Attribute* pAttr = Core::gamestate.attributes[ai];
4159  AttributeValue& av = attribute( ai );
4160 
4161  av = attribute( ai );
4162  av.cap( pAttr->default_cap );
4163  }
4164 }
4165 
4167 {
4168  return _last_textcolor;
4169 }
4170 
4172 {
4173  _last_textcolor = new_color;
4174 }
4175 
4176 unsigned int Character::guildid() const
4177 {
4178  auto g = guild();
4179  return ( g != nullptr ) ? g->guildid() : 0;
4180 }
4181 
4187 void Character::addBuff( u16 icon, u16 duration, u32 cl_name, u32 cl_descr,
4188  const std::vector<u32>& arguments )
4189 {
4190  // Icon is already present, must send a remove packet first or client will not update
4191  delBuff( icon );
4192 
4193  Core::gameclock_t end = Core::read_gameclock() + duration;
4194  buffs_[icon] = {end, cl_name, cl_descr, arguments};
4195 
4196  if ( client != nullptr )
4197  send_buff_message( this, icon, true, duration, cl_name, cl_descr, arguments );
4198 }
4199 
4207 {
4208  auto b = buffs_.find( icon );
4209 
4210  if ( b == buffs_.end() )
4211  return false;
4212 
4213  buffs_.erase( b );
4214  if ( client != nullptr )
4215  send_buff_message( this, icon, false );
4216  return true;
4217 }
4218 
4225 {
4226  for ( auto it = buffs_.begin(); it != buffs_.end(); ++it )
4227  delBuff( it->first );
4228 }
4229 
4235 {
4236  if ( client == nullptr )
4237  return;
4238 
4239  for ( auto it = buffs_.begin(); it != buffs_.end(); ++it )
4240  {
4241  int duration = it->second.end - Core::read_gameclock();
4242  if ( duration < 0 )
4243  duration = 0;
4244  else if ( duration > 0xFFFF )
4245  duration = 0xFFFF;
4246 
4247  send_buff_message( this, it->first, true, static_cast<u16>( duration ), it->second.cl_name,
4248  it->second.cl_descr, it->second.arguments );
4249  }
4250 }
4251 
4253 {
4254  size_t size = base::estimatedSize() + uclang.capacity() + privs.estimatedSize() +
4255  settings.estimatedSize() + sizeof( Core::AccountRef ) /*acct*/
4256  + sizeof( Network::Client* ) /*client*/
4257  + sizeof( u32 ) /*registered_house*/
4258  + sizeof( unsigned char ) /*cmdlevel_*/
4259  + sizeof( u8 ) /*dir*/
4260  + sizeof( u16 ) /*lastx*/
4261  + sizeof( u16 ) /*lasty*/
4262  + sizeof( s8 ) /*lastz*/
4263  + sizeof( MOVEREASON ) /*move_reason*/
4264  + sizeof( Core::MOVEMODE ) /*movemode*/
4265  + sizeof( time_t ) /*disable_regeneration_until*/
4266  + sizeof( u16 ) /*truecolor*/
4267  + sizeof( u32 ) /*trueobjtype*/
4268  + sizeof( Core::UGENDER ) /*gender*/
4269  + sizeof( Core::URACE ) /*race*/
4270  + sizeof( short ) /*gradual_boost*/
4271  + sizeof( u32 ) /*last_corpse*/
4272  + sizeof( GOTTEN_ITEM_TYPE ) /*gotten_item_source*/
4273  + sizeof( Core::TargetCursor* ) /*tcursor2*/
4274  + sizeof( weak_ptr<Core::Menu> ) /*menu*/
4275  + sizeof( u16 ) /*_last_textcolor*/
4276  + sizeof( ref_ptr<Core::WornItemsContainer> ) /*wornitems_ref*/
4277  + sizeof( unsigned short ) /*ar_*/
4278  + sizeof( Items::UWeapon* ) /*weapon*/
4279  + sizeof( Items::UArmor* ) /*shield*/
4280  + sizeof( unsigned char ) /*concealed_*/
4281  + sizeof( unsigned short ) /*stealthsteps_*/
4282  + sizeof( unsigned int ) /*mountedsteps_*/
4284  sizeof( Core::UOExecutor* ) /*script_ex*/
4285  + sizeof( Character* ) /*opponent_*/
4286  + sizeof( Core::polclock_t ) /*swing_timer_start_clock_*/
4287  + sizeof( Core::OneShotTask* ) /*swing_task*/
4288  + sizeof( Core::OneShotTask* ) /*spell_task*/
4289  + sizeof( Core::gameclock_t ) /*created_at*/
4290  + sizeof( Core::polclock_t ) /*criminal_until_*/
4291  + sizeof( Core::OneShotTask* ) /*repsys_task_*/
4292  + sizeof( Core::OneShotTask* ) /*party_decline_timeout_*/
4293  + sizeof( Core::AttributeFlags<PRIV_FLAGS> ) /*cached_settings*/
4294  + sizeof( Core::AttributeFlags<MOB_FLAGS> ) /*mob_flags_*/
4295  ;
4296 
4297  size += 3 * sizeof( AttributeValue* ) + attributes.capacity() * sizeof( AttributeValue );
4298  size += 3 * sizeof( VitalValue* ) + vitals.capacity() * sizeof( VitalValue );
4299  size += 3 * sizeof( Items::UArmor** ) + armor_.capacity() * sizeof( Items::UArmor* );
4300  size += 3 * sizeof( Core::ItemRef* ) + remote_containers_.capacity() * sizeof( Core::ItemRef );
4301 
4302  size += 3 * sizeof( void* ) + opponent_of.size() * ( sizeof( Character* ) + 3 * sizeof( void* ) );
4303 
4304  size += aggressor_to_.size() * ( sizeof( Core::CharacterRef ) + sizeof( Core::polclock_t ) +
4305  ( sizeof( void* ) * 3 + 1 ) / 2 );
4306  size += lawfully_damaged_.size() * ( sizeof( Core::CharacterRef ) + sizeof( Core::polclock_t ) +
4307  ( sizeof( void* ) * 3 + 1 ) / 2 );
4308 
4309  size +=
4310  3 * sizeof( void* ) + to_be_reportable_.size() * ( sizeof( USERIAL ) + 3 * sizeof( void* ) );
4311  size +=
4312  3 * sizeof( void* ) + reportable_.size() * ( sizeof( reportable_t ) + 3 * sizeof( void* ) );
4313 
4314  size +=
4315  3 * sizeof( void* ) + buffs_.size() * ( sizeof( u16 ) + sizeof( Buff ) + sizeof( void* ) );
4316 
4317  return size;
4318 }
4319 
4321 {
4322  if ( realm )
4324 }
4325 } // namespace Mobile
4326 } // namespace Pol
bool empty() const
Definition: scrdef.h:41
u16 strength() const
Definition: charactr.cpp:4085
Contents::const_iterator const_iterator
Definition: containr.h:115
unsigned char u8
Definition: rawtypes.h:25
const int VITAL_LOWEST_REGENRATE
Definition: vital.h:51
bool newbie() const
Definition: item.h:338
ToBeReportableList to_be_reportable_
Definition: charactr.h:847
bool poisoned() const
Definition: charactr.h:979
std::vector< unsigned short > layers
Definition: layers.h:23
#define UOBJ_GARGOYLE_FEMALE
Definition: objtype.h:136
void register_with_supporting_multi(Item *item)
Definition: ufunc.cpp:1875
std::vector< Items::Item * > Contents
Definition: containr.h:113
void check_weather_region_change(bool force=false)
Definition: charactr.cpp:3535
const unsigned int VITAL_LOWEST_MAX_HUNDREDTHS
Definition: vital.h:59
static Item * create(u32 objtype, u32 serial=0)
Definition: itemcr.cpp:53
void unload_armor_zones()
Definition: charactr.cpp:252
unsigned int gameclock_t
Definition: gameclck.h:14
virtual void walk_on(Mobile::Character *chr)
Definition: chrituse.cpp:90
Character * opponent_
Definition: charactr.h:828
virtual void walk_on(Mobile::Character *chr) POL_OVERRIDE
Definition: house.cpp:964
bool setting_enabled(const char *setting) const
Definition: charactr.cpp:1096
unsigned int tile_flags(unsigned short tilenum)
Definition: polfile2.cpp:49
#define UOBJ_GARGOYLE_MALE
Definition: objtype.h:135
bool can_add_to_slot(u8 &slotIndex)
Definition: containr.cpp:178
void select_opponent(u32 opp_serial)
Definition: charactr.cpp:3044
unsigned int guildid() const
Definition: charactr.cpp:4176
bool can_moveanydist() const
Definition: charactr.cpp:1256
Core::gameclock_t created_at
Definition: charactr.h:906
ref_ptr< Bscript::EScriptProgram > find_script2(const ScriptDef &script, bool complain_if_not_found, bool cache_script)
Definition: scrstore.cpp:83
static void swing_task_func(Character *chr)
Definition: charactr.cpp:2776
virtual size_t estimatedSize() const POL_OVERRIDE
Definition: charactr.cpp:4252
static const char custom_house_z_xlate_table[CUSTOM_HOUSE_NUM_PLANES]
Definition: customhouses.h:145
Vital * FindVital(const std::string &str)
Definition: vital.cpp:83
Character * get_attackable_opponent() const
Definition: charactr.cpp:2913
unsigned int find_sumof_objtype_noninuse(u32 objtype) const
Definition: containr.cpp:471
bool in_debugger_holdlist() const
Definition: osmod.cpp:869
#define UOBJ_DEATH_SHROUD
Definition: objtype.h:219
std::string remove_string(const char *propname)
Definition: cfgfile.cpp:381
bool is_murderer() const
Definition: repsys.cpp:776
bool has_active_prompt() const
Definition: charactr.cpp:453
u16 dexterity() const
Definition: charactr.cpp:4089
void set_opponent(Character *opponent, bool inform_old_opponent=true)
Definition: charactr.cpp:2994
virtual bool can_add(const Items::Item &item) const
Definition: containr.cpp:168
u8 get_flag1(Network::Client *other_client) const
Definition: charactr.cpp:1771
void add_item_to_world(Items::Item *item)
Definition: uworld.cpp:31
Core::UACTION mounted_anim() const
Definition: weapon.cpp:408
void send_remove_if_hidden_ghost(Character *chr, Network::Client *client)
Definition: charactr.cpp:2027
unsigned short default_light_level
Definition: ssopt.h:48
virtual void printSelfOn(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: charactr.cpp:758
void send_full_corpse(Client *client, const Item *item)
Definition: ufunc.cpp:660
void on_swing_failure(Character *attacker)
Definition: charactr.cpp:2952
unsigned char lock() const
Definition: charactr.h:174
unsigned char weathertype
Definition: miscrgn.h:69
Items::Item * create_backpack()
Definition: charactr.cpp:2009
ExternalObject extobj
Definition: settings.h:30
bool check_unequip_script()
Definition: item.cpp:1064
#define UPDATE_CHECKPOINT()
Definition: checkpnt.h:35
unsigned char concealed() const
Definition: charactr.h:955
const u8 CHAR_FLAG1_FLYING
Definition: pktdef.h:102
bool deafened() const
Definition: charactr.cpp:4061
void PropagateMove(Character *chr)
Definition: charactr.cpp:2683
SystemState systemstate
Definition: systemstate.cpp:12
bool call(Bscript::BObjectImp *p0)
Definition: syshook.cpp:44
void send_short_statmsg(Network::Client *client, Mobile::Character *chr)
Definition: statmsg.cpp:235
unsigned short cap() const
Definition: charactr.h:176
Network::Client * client
Definition: charactr.h:871
polclock_t polclock()
Definition: polclock.cpp:72
void revoke_privilege(const char *priv)
Definition: charactr.cpp:1193
Core::PolConfig config
Definition: systemstate.h:43
void extract(Contents &cnt)
Definition: containr.cpp:322
void seterror(bool err)
Definition: executor.h:437
bool party_can_loot() const
Definition: party.cpp:1492
std::map< u16, Buff > buffs_
Definition: charactr.h:910
MobileCont lawfully_damaged_
Definition: charactr.h:844
bool walkheight(unsigned short x, unsigned short y, short oldz, short *newz, Multi::UMulti **pmulti, Items::Item **pwalkon, bool doors_block, Core::MOVEMODE movemode, short *gradual_boost=nullptr)
Definition: realmfunc.cpp:340
bool consume_projectile(Core::UContainer *cont) const
Definition: weapon.cpp:432
unsigned char tilelayer(unsigned short tilenum)
Definition: polfile2.cpp:22
void send_create_ghost(Character *chr, Network::Client *client)
Definition: charactr.cpp:2037
#define SOUND_EFFECT_FEMALE_DEFENSE
Definition: sfx.h:28
bool strong_enough_to_equip(const Items::Item *item) const
Definition: charactr.cpp:1350
unsigned short min_value(void) const
Definition: dice.cpp:178
bool is_intrinsic() const
Tells eather an equipment is intrinsic or not Intrinsic equipment is, by example, NPCs "natural" weap...
Definition: equipmnt.cpp:104
Core::UOExecutor * script_ex
Definition: charactr.h:867
ExportedFunction * combat_advancement_hook
Definition: syshook.h:70
time_t disable_regeneration_until
Definition: charactr.h:834
bool check_unequiptest_scripts(Mobile::Character *chr)
Definition: item.cpp:1142
unsigned int release()
Definition: refptr.h:126
Core::polclock_t polclock
Definition: charactr.h:276
unsigned short hit_sound() const
Definition: weapon.cpp:414
void add_remote_container(Items::Item *)
Definition: charactr.cpp:3991
#define UOBJ_ELF_FEMALE
Definition: objtype.h:131
std::string all_privs() const
Definition: charactr.cpp:1173
T * get() const
Definition: refptr.h:176
SystemHooks system_hooks
Definition: uvars.h:190
void grant_privilege(const char *priv)
Definition: charactr.cpp:1184
#define POLLOG_INFO
Definition: logfacility.h:213
bool target_cursor_busy() const
Definition: charactr.cpp:4098
void printWornItems(Clib::StreamWriter &sw_pc, Clib::StreamWriter &sw_equip) const
Definition: charactr.cpp:767
static const SkillStatCap DEFAULT
virtual unsigned short ar() const
Definition: armor.cpp:131
bool in_range(const Mobile::Character *wielder, const Mobile::Character *target) const
Definition: weapon.cpp:448
unsigned short base_str_req
Definition: itemdesc.h:125
MusicDef * musicdef
Definition: uvars.h:152
int charindex() const
Definition: charactr.cpp:533
void calc_single_attribute(const Attribute *pAttr)
Definition: charactr.cpp:1630
virtual void on_facing_changed() POL_OVERRIDE
Definition: charactr.cpp:1748
bool is_attackable(Character *who) const
Definition: charactr.cpp:2878
ExportedFunction * warmode_change
Definition: syshook.h:82
void notify_resurrected(Mobile::Character &whoressed)
Definition: realm.cpp:157
virtual void on_color_changed() POL_OVERRIDE
Definition: charactr.cpp:1676
Core::Dice damage_dice
Definition: wepntmpl.h:44
unsigned int remove_ulong(const char *propname)
Definition: cfgfile.cpp:461
void set(ENUM flag)
Definition: uobject.h:113
Items::Item * find(u32 serial) const
Definition: containr.cpp:620
bool is_visible_to_me(const Character *chr) const
Definition: charactr.cpp:2658
void heal_damage_hundredths(unsigned int damage)
When a Mobile is Healed.
Definition: charactr.cpp:1979
ref_ptr< Core::WornItemsContainer > wornitems
Definition: charactr.h:787
bool is_visible() const
Definition: charactr.h:936
void calc_vital_stuff(bool i_mod=true, bool v_mod=true)
Definition: charactr.cpp:1581
void add(const char *str)
Definition: strset.cpp:19
bool has_active_client() const
Definition: charactr.cpp:448
bool enforce_mount_objtype
Definition: polcfg.h:95
bool get(ENUM flag) const
Definition: uobject.h:108
Mobile::Character * get_character(int index)
Definition: account.cpp:169
bool inrange(const UObject *c1, unsigned short x, unsigned short y)
Definition: ufunc.cpp:454
void check_justice_region_change()
Definition: charactr.cpp:3448
virtual void get_hitscript_params(double damage, Items::UArmor **parmor, unsigned short *rawdamage)
Definition: charactr.cpp:1899
int remove_int(const char *propname)
Definition: cfgfile.cpp:340
unsigned char cmdlevel() const
Definition: charactr.h:993
Core::TargetCursor * tcursor2
Definition: charactr.h:861
unsigned short calc_thru_damage(double damage, unsigned short ar)
Definition: charactr.cpp:1847
Items::UWeapon * weapon
Definition: charactr.h:783
void attack(Character *opponent)
Definition: charactr.cpp:3223
bool frozen() const
Definition: charactr.h:969
#define THREAD_CHECKPOINT(thread, check)
Definition: polsig.h:48
Item * find_legal_item(const Character *chr, u32 serial, bool *additlegal, bool *isRemoteContainer)
Definition: ufunc.cpp:958
Core::WeatherRegion * weather_region
Definition: cgdata.h:75
std::string name
Definition: layers.h:21
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:856
virtual void setfacing(u8 newfacing) POL_OVERRIDE
Definition: charactr.cpp:1766
virtual bool can_be_renamed_by(const Character *chr) const
Definition: charactr.cpp:1230
virtual void repsys_on_damage(Character *defender)
[14] Mobile (MA) Damages Mobile (MB)
Definition: repsys.cpp:872
bool use_insurance()
Returns current insurance value and resets it to false.
Definition: item.cpp:299
void send_light(Client *client, int lightlevel)
Definition: ufunc.cpp:766
Items::Item * create_death_shroud()
Definition: charactr.cpp:1997
bool connected() const
Definition: charactr.cpp:438
u32 USERIAL
Definition: utype.h:21
static const ExtStatBarFollowers DEFAULT
#define FUNCTION_CHECKPOINT(func, check)
Definition: polsig.h:50
bool logged_in() const
Definition: charactr.cpp:428
Clib::StringSet privs
Definition: charactr.h:892
virtual double armor_absorb_damage(double damage)
Definition: charactr.cpp:1874
std::string uclang
Definition: charactr.h:872
void remove(const char *str)
Definition: strset.cpp:23
std::vector< AttributeValue > attributes
Definition: charactr.h:835
virtual void register_object(UObject *obj)
Definition: multis.cpp:60
CmdLevels cmdlevels
Definition: uvars.h:137
Items::Item * create_death_robe()
Definition: charactr.cpp:2003
bool gflag_in_system_load
Definition: state.h:39
static void InRange(u16 x, u16 y, const Realms::Realm *realm, unsigned range, F &&f)
Definition: uworld.h:235
std::vector< Items::UArmor * > armor_
Definition: charactr.h:785
const Mobile::Attribute & attribute() const
Definition: weapon.cpp:360
void readfrom(const std::string &str)
Definition: strset.cpp:33
virtual Item * clone() const
Definition: item.cpp:56
void disable_regeneration_for(int seconds)
Definition: charactr.cpp:3060
unsigned short max_weapon_damage() const
Definition: charactr.cpp:3127
#define UOBJ_GOLD_COIN
Definition: objtype.h:209
virtual T * getregion(xcoord x, ycoord y, Realms::Realm *realm)
Definition: region.h:126
unsigned int mount
Definition: extobj.h:32
bool on_mount() const
Definition: charactr.cpp:1490
const short ATTRIBUTE_MIN_INTRINSIC_MOD
Definition: attribute.h:75
virtual size_t estimatedSize() const
Definition: uobject.cpp:106
bool is_projectile() const
Definition: weapon.cpp:377
const u8 CHAR_FLAG1_INVISIBLE
Definition: pktdef.h:98
LightDef * lightdef
Definition: uvars.h:150
int current_ones() const
Definition: charactr.h:193
MoveDelta move_delta[8]
Definition: ufacing.cpp:16
void play_moving_effect(const UObject *src, const UObject *dst, u16 effect, u8 speed, u8 loop, u8 explode)
Definition: ufunc.cpp:1039
virtual void add(Items::Item *item)
Definition: containr.cpp:194
static Core::MOVEMODE decode_movemode(const std::string &str)
Definition: charactr.cpp:772
virtual bool setgraphic(u16 newobjtype) POL_OVERRIDE
Definition: charactr.cpp:1659
const WeaponDesc & descriptor() const
Definition: weapon.cpp:426
void send_item_to_inrange(const Item *item)
Definition: ufunc.cpp:706
void set_setting(const char *setting, bool value)
Definition: charactr.cpp:1157
Mobile::Character * chr
Definition: client.h:182
bool can_rename(const Character *chr) const
Definition: charactr.cpp:1236
#define passert_r(exp, reason)
Definition: passert.h:66
bool can_freemove() const
Definition: charactr.cpp:1271
#define ITEM_ELEM_PTR(elem)
Definition: containr.h:39
Core::UGENDER gender
Definition: charactr.h:918
virtual bool script_isa(unsigned isatype) const POL_OVERRIDE
Definition: uoscrobj.cpp:4604
unsigned short delay() const
Definition: weapon.cpp:355
const u8 CHAR_FLAG1_POISONED
Definition: pktdef.h:101
void updateEquipableProperties(Items::Item *item)
Definition: charactr.cpp:2555
MOVEMODE
Definition: uconst.h:79
void send_item_move_failure(Network::Client *client, u8 reason)
Definition: ufunc.cpp:818
bool private_say_above(Character *chr, const UObject *obj, const char *text, unsigned short font, unsigned short color, unsigned int journal_print)
Definition: ufunc.cpp:1328
unsigned short projectile_sound() const
Definition: weapon.cpp:383
void addBuff(u16 icon, u16 duration, u32 cl_name, u32 cl_descr, const std::vector< u32 > &arguments)
Definition: charactr.cpp:4187
bool consume(const Core::Vital *pVital, VitalValue &vv, unsigned int amt)
Definition: charactr.cpp:1540
unsigned short getmidi() const
Definition: musicrgn.cpp:32
void undo_get_item(Mobile::Character *chr, Items::Item *item)
Definition: getitem.cpp:260
#define UOBJ_GARGOYLE_FEMALE_GHOST
Definition: objtype.h:138
double remove_double(const char *propname, double dflt)
Definition: cfgfile.cpp:448
void set_dirty()
Definition: uobject.h:291
int default_accessible_range
Definition: ssopt.h:47
bool no_drop() const
Definition: item.cpp:310
virtual bool script_isa(unsigned isatype) const POL_OVERRIDE
Definition: uoscrobj.cpp:4627
std::string hexint(unsigned short v)
Definition: strutil.cpp:23
bool valid_equip_layer(int layer)
Definition: item.h:383
const std::string & name() const
Definition: scrdef.h:45
ExportedFunction * get_maximum_func
Definition: vital.h:42
MobileCont aggressor_to_
Definition: charactr.h:843
unsigned short u16
Definition: rawtypes.h:26
unsigned int u32
Definition: rawtypes.h:27
void send_remove_character(Client *client, const Character *chr)
Definition: ufunc.cpp:355
#define UOBJ_HUMAN_MALE
Definition: objtype.h:125
void send_remove_character_to_nearby_cantsee(const Character *chr)
Definition: ufunc.cpp:389
#define RANGE_VISUAL
Definition: uconst.h:72
Core::UContainer * trade_container()
Definition: charactr.cpp:4142
virtual const char * classname() const POL_OVERRIDE
Definition: charactr.cpp:753
const u16 AOS
Definition: client.h:75
void clear()
Definition: refptr.h:283
POL_NORETURN void throw_error(const std::string &errmsg) const
Definition: cfgfile.cpp:285
void send_move_mobile_to_nearby_cansee(const Character *chr)
Definition: ufunc.cpp:1905
Multi::UMulti * system_find_multi(u32 serial)
Definition: fnsearch.cpp:50
void send_poisonhealthbar(Client *client, const Character *chr)
Definition: ufunc.cpp:186
bool consume(unsigned int hamt)
Definition: charactr.h:225
virtual void repsys_on_attack(Character *defender)
[13] Mobile (MA) Attacks Mobile (MA)
Definition: repsys.cpp:809
void spend_gold(unsigned int amount)
Definition: charactr.cpp:1321
void readCommonProperties(Clib::ConfigElem &elem)
Definition: charactr.cpp:802
void send_move(Client *client, const Character *chr)
Definition: ufunc.cpp:174
bool warmode() const
Definition: charactr.cpp:3067
void on_loggoff_party(Mobile::Character *chr)
Definition: party.cpp:878
virtual void cancel(void) POL_OVERRIDE
Definition: schedule.cpp:143
virtual void destroy()
Definition: uobject.cpp:122
void send_midi(Client *client, u16 midi)
Definition: ufunc.cpp:1867
bool move(unsigned char dir)
Definition: charactr.cpp:3757
bool CustomHousingMove(unsigned char i_dir)
Definition: charactr.cpp:3706
virtual class UHouse * as_house()
Definition: multis.cpp:55
signed short s16
Definition: rawtypes.h:30
void unequip(Items::Item *item)
Definition: charactr.cpp:1464
unsigned short get_random_damage() const
Definition: weapon.cpp:365
ExportedFunction * get_regenrate_func
Definition: vital.h:41
bool face(Core::UFACING i_facing, int flags=0)
Definition: charactr.cpp:3678
void send_goxyz(Client *client, const Character *chr)
Definition: ufunc.cpp:149
UOExecutor * create_script_executor()
Definition: scrsched.cpp:644
#define UOBJ_GARGOYLE_MALE_GHOST
Definition: objtype.h:137
bool can_hearghosts() const
Definition: charactr.cpp:1246
bool mightsee(const Items::Item *item) const
Definition: charactr.cpp:4025
const int VITAL_HIGHEST_REGENRATE
Definition: vital.h:52
unsigned char aux
Definition: miscrgn.h:71
ref_ptr< Core::UContainer > trading_cont
Definition: charactr.h:856
Module::UOExecutorModule * prompt_uoemod
Definition: cgdata.h:64
weak_ptr< Core::Menu > menu
Definition: charactr.h:862
int maximum() const
Definition: charactr.h:199
void send_damage(Character *attacker, Character *defender, u16 damage)
Definition: ufunc.cpp:2130
Core::ExportedFunction * getintrinsicmod_func
Definition: attribute.h:47
int random_int(int i)
Definition: random.cpp:34
Core::OneShotTask * repsys_task_
Definition: charactr.h:846
unsigned int _current
Definition: charactr.h:252
void send_feature_enable(Client *client)
Definition: ufunc.cpp:1953
void Send(Client *client, int len=-1) const
Definition: packethelper.h:69
const AttributeValue & attribute(unsigned attrid) const
Definition: charactr.h:1051
Core::MusicRegion * music_region
Definition: cgdata.h:74
u32 UseCharSerialNumber(u32 serial)
Definition: ufunc.cpp:126
unsigned short raw_to_base(unsigned int raw)
Definition: skilladv.cpp:45
void play_sound_effect(const UObject *center, u16 effect)
Definition: ufunc.cpp:1015
#define UOBJ_CORPSE
Definition: objtype.h:218
Core::CharacterRef trading_with
Definition: charactr.h:857
virtual unsigned short ar() const
Definition: charactr.h:1008
JusticeDef * justicedef
Definition: uvars.h:148
bool doors_block() const
Definition: charactr.cpp:3629
Character(u32 objtype, Core::UOBJ_CLASS uobj_class=Core::UOBJ_CLASS::CLASS_CHARACTER)
Definition: charactr.cpp:259
bool orphan() const
Definition: baseobject.h:119
unsigned char cmdlevel
Definition: cmdlevel.h:39
std::string getencodedquotedstring(const std::string &in)
Definition: strutil.cpp:235
#define UOBJ_HUMAN_MALE_GHOST
Definition: objtype.h:127
void refresh_cached_settings(bool update=true)
Definition: charactr.cpp:1101
const unsigned POLCLASS_CONTAINER
Definition: polclass.h:18
virtual void readProperties(Clib::ConfigElem &elem) POL_OVERRIDE
Definition: charactr.cpp:1082
bool has_los(const Core::ULWObject &att, const Core::ULWObject &tgt) const
Definition: realmlos.cpp:146
bool has_privilege(const char *priv) const
Definition: charactr.cpp:1091
#define MOVE_ITEM_FAILURE_UNKNOWN
Definition: pktdef.h:38
bool is_trading() const
Definition: charactr.cpp:4117
virtual void inform_engaged(Character *engaged)
Definition: charactr.cpp:2965
bool paralyzed() const
Definition: charactr.h:974
const short ATTRIBUTE_MAX_INTRINSIC_MOD
Definition: attribute.h:76
virtual void inform_moved(Character *moved)
Definition: charactr.cpp:2988
void getpos_ifmove(Core::UFACING i_facing, unsigned short *px, unsigned short *py)
Definition: charactr.cpp:2770
bool manual_set_swing_timer(int time)
Definition: charactr.cpp:2843
ref_ptr< Mobile::Character > CharacterRef
Definition: reftypes.h:42
virtual void inform_leftarea(Character *wholeft)
Definition: charactr.cpp:2978
Core::polclock_t swing_timer_start_clock_
Definition: charactr.h:830
std::vector< Mobile::Attribute * > attributes
Definition: uvars.h:176
const char * zone_to_zone_name(unsigned short zone)
Definition: charactr.cpp:196
Core::UACTION anim() const
Definition: weapon.cpp:402
#define passert(exp)
Definition: passert.h:62
Core::MOVEMODE movemode
Definition: charactr.h:811
int regenrate() const
Definition: charactr.h:202
void remove(ENUM flag)
Definition: uobject.h:114
void setrealm(Item *item, void *arg)
Definition: ufunc.cpp:1571
virtual void printOn(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: charactr.cpp:763
void send_death_message(Character *chr_died, Item *corpse)
Definition: ufunc.cpp:1497
void calc_single_vital(const Core::Vital *pVital)
Definition: charactr.cpp:1600
void send_highlight() const
Definition: charactr.cpp:2937
unsigned short miss_sound() const
Definition: weapon.cpp:420
virtual const char * target_tag() const POL_OVERRIDE
Definition: charactr.cpp:4149
void send_fight_occuring(Client *client, Character *opponent)
Definition: ufunc.cpp:2121
#define POLLOG
Definition: logfacility.h:219
signed char s8
Definition: rawtypes.h:29
int polclock_t
Definition: polclock.h:26
std::string extract() const
Definition: strset.cpp:46
#define UOBJ_HUMAN_FEMALE_GHOST
Definition: objtype.h:128
void add_at_random_location(Items::Item *item)
Definition: containr.cpp:291
ClientGameData * gd
Definition: client.h:252
void remove_mobile(const Mobile::Character &chr, WorldChangeReason reason)
Definition: realm.cpp:228
#define CLEAR_CHECKPOINT()
Definition: checkpnt.h:37
bool RunEnterScript(Mobile::Character *chr)
Definition: guardrgn.cpp:55
Module::UnicodeExecutorModule * prompt_uniemod
Definition: cgdata.h:68
ReportableList reportable_
Definition: charactr.h:848
Core::AttributeFlags< PRIV_FLAGS > cached_settings
Definition: charactr.h:895
Core::UContainer * container
Definition: item.h:256
#define UOBJ_BACKPACK
Definition: objtype.h:202
unsigned char default_character_height
Definition: ssopt.h:97
Clib::StringSet settings
Definition: charactr.h:893
gameclock_t read_gameclock()
Reads the current value of the game clock.
Definition: gameclck.cpp:57
Core::UACTION weapon_anim() const
Definition: charactr.cpp:3154
int maximum_ones() const
Definition: charactr.h:200
#define GET_ITEM_PTR(itr)
Definition: containr.h:38
bool isActive() const
Definition: client.h:306
const u32 objtype_
Definition: uobject.h:249
Core::URACE race
Definition: charactr.h:919
void setname(const std::string &)
Definition: uobject.cpp:206
GameState gamestate
Definition: uvars.cpp:74
ExportedFunction * pushthrough_hook
Definition: syshook.h:73
void send_full_statmsg(Network::Client *client, Mobile::Character *chr)
Definition: statmsg.cpp:32
bool can_be_heard_as_ghost() const
Definition: charactr.cpp:1251
Attribute * next
Definition: attribute.h:45
time_t poltime()
Definition: polclock.cpp:102
Mobile::Character * find_character(u32 serial)
Definition: fnsearch.cpp:60
void equip(Items::Item *item)
Definition: charactr.cpp:1433
const u8 CHAR_FLAG1_WARMODE
Definition: pktdef.h:99
virtual void Send(Client *client) POL_OVERRIDE
Definition: packetdefs.cpp:881
void send_realm_change(Client *client, Realms::Realm *realm)
Definition: ufunc.cpp:2034
void move_item(Item *item, UFACING facing)
Definition: ufunc.cpp:1601
const std::string & leavetext() const
Definition: guardrgn.h:77
bool is_house_editing() const
Definition: charactr.cpp:464
const Core::ScriptDef & hit_script() const
Definition: weapon.h:134
void consume_sumof_objtype_noninuse(u32 objtype, unsigned int amount)
Definition: containr.cpp:495
bool delBuff(u16 icon)
Definition: charactr.cpp:4206
bool cache_interactive_scripts
Definition: polcfg.h:51
#define UOBJ_ELF_MALE_GHOST
Definition: objtype.h:132
void set_current_ones(const Core::Vital *pVital, VitalValue &vv, unsigned int ones)
Definition: charactr.cpp:1553
#define ctBEu32(x)
Definition: clib_endian.h:45
SettingsManager settingsManager
Definition: settings.cpp:14
Core::AttributeFlags< MOB_FLAGS > mob_flags_
Definition: charactr.h:896
static void InVisualRange(const UObject *obj, F &&f)
Definition: uworld.h:245
bool is_concealed_from_me(const Character *chr) const
Definition: charactr.cpp:2653
const std::string & entertext() const
Definition: guardrgn.h:72
unsigned numVitals
Definition: uvars.h:198
bool contains(const char *str) const
Definition: strset.cpp:14
Vital * next
Definition: vital.h:39
virtual void destroy() POL_OVERRIDE
Definition: charactr.cpp:482
void commit_to_reportables()
Definition: repsys.cpp:1172
const unsigned POLCLASS_SPELLBOOK
Definition: polclass.h:21
Character * get_opponent() const
Definition: charactr.cpp:2868
void MoveCharacterWorldPosition(unsigned short oldx, unsigned short oldy, unsigned short newx, unsigned short newy, Mobile::Character *chr, Realms::Realm *oldrealm)
Definition: uworld.cpp:171
bool movable() const
Definition: item.h:300
StateManager stateManager
Definition: state.cpp:8
const u8 CHAR_FLAG1_YELLOWHEALTH
Definition: pktdef.h:100
Mobile::Character * system_find_mobile(u32 serial)
Definition: fnsearch.cpp:32
virtual void on_death(Items::Item *corpse)
Definition: charactr.cpp:2137
virtual void inform_disengaged(Character *disengaged)
Definition: charactr.cpp:2957
#define DECLARE_CHECKPOINT
Definition: checkpnt.h:33
void send_update_hits_to_inrange(Mobile::Character *chr)
Definition: statmsg.cpp:263
bool remove_prop(const char *propname, std::string *value)
Definition: cfgfile.cpp:128
const unsigned ATTRIBUTE_MAX_BASE
Definition: attribute.h:70
ref_ptr< Items::Item > ItemRef
Definition: reftypes.h:43
static const MovementCostMod DEFAULT
#define UOBJ_HUMAN_FEMALE
Definition: objtype.h:126
void send_weather(Client *client, u8 type, u8 severity, u8 aux)
Definition: ufunc.cpp:776
void run_hit_script(Character *defender, double damage)
Definition: charactr.cpp:1914
static Guild * FindOrCreateGuild(unsigned int guildid, unsigned int memberserial)
Definition: guilds.cpp:236
int intrinsic_mod() const
Definition: charactr.h:172
void load_armor_zones()
Definition: charactr.cpp:214
Core::AccountRef acct
Definition: charactr.h:914
unsigned short movecost(const Mobile::Character *chr, int carry_perc, bool running, bool mounted)
Definition: movecost.cpp:87
void build_owncreate(const Character *chr, PktOut_78 *owncreate)
Definition: ufunc.cpp:282
int editing_floor_num
Definition: house.h:92
Core::JusticeRegion * justice_region
Definition: cgdata.h:70
ref_ptr< Accounts::Account > AccountRef
Definition: reftypes.h:45
virtual void printProperties(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: charactr.cpp:549
ArmorZones armorzones
Definition: uvars.h:194
bool can_speedhack() const
Definition: charactr.cpp:1266
#define PKTIN_02_DIR_RUNNING_BIT
Definition: pktdef.h:76
Items::Item * system_find_item(u32 serial)
Definition: fnsearch.cpp:41
void send_buff_message(Character *chr, u16 icon, bool show, u16 duration, u32 cl_name, u32 cl_descr, std::vector< u32 > arguments)
Definition: ufunc.cpp:2188
#define PKTIN_02_FACING_MASK
Definition: pktdef.h:75
u8 slot_index() const
Definition: item.h:358
unsigned short max_value(void) const
Definition: dice.cpp:188
virtual void inform_criminal(Character *thecriminal)
Definition: charactr.cpp:2973
virtual void printDebugProperties(Clib::StreamWriter &sw) const
Definition: uobject.cpp:275
bool invisible() const
Definition: item.h:324
Core::UContainer * backpack() const
Definition: charactr.cpp:1276
void restart_decay_timer()
Definition: item.cpp:974
bool hidden_turns_count
Definition: ssopt.h:55
bool can_clothe(const Character *chr) const
Definition: charactr.cpp:1241
#define INFO_PRINT_TRACE(n)
Definition: logfacility.h:226
#define ISTRINGSTREAM
Definition: stlutil.h:73
bool is_equipped(const Items::Item *item) const
Definition: charactr.cpp:1342
Core::Spellbook * spellbook(u8 school) const
Definition: charactr.cpp:1281
#define UOBJ_GAMEMASTER
Definition: objtype.h:200
Module::UOExecutorModule * target_cursor_uoemod
Definition: cgdata.h:61
void(* on_menu_selection)(Network::Client *client, Core::MenuItem *mi, Core::PKTIN_7D *msg)
Definition: charactr.h:863
Items::UArmor * choose_armor() const
Definition: charactr.cpp:3140
unsigned short pol_distance(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
Definition: ufunc.cpp:481
virtual void readProperties(Clib::ConfigElem &elem)
Definition: uobject.cpp:287
void position_changed(void)
Definition: charactr.cpp:3590
void notify_unhid(Mobile::Character &whounhid)
Definition: realm.cpp:149
bool RunLeaveScript(Mobile::Character *chr)
Definition: guardrgn.cpp:71
Realms::Realm * realm
Definition: baseobject.h:56
Items::Item * find_wornitem(u32 find_serial) const
Definition: charactr.cpp:1499
const u8 CHAR_FLAG1_GENDER
Definition: pktdef.h:104
void check_music_region_change()
Definition: charactr.cpp:3515
Items::UArmor * shield
Definition: charactr.h:784
unsigned lightlevel
Definition: miscrgn.h:57
#define SOUND_EFFECT_MALE_DEFENSE
Definition: sfx.h:34
static std::string encode_movemode(Core::MOVEMODE movemode)
Definition: charactr.cpp:788
CmdLevel * find_cmdlevel(const char *name)
Definition: cmdlevel.cpp:84
virtual void printOn(Clib::StreamWriter &) const
Definition: uobject.cpp:332
unsigned short random_weapon_damage() const
Definition: charactr.cpp:3117
bool can_face(Core::UFACING i_facing)
Definition: charactr.cpp:3650
void set_warmode(bool warmode)
Definition: charactr.cpp:3072
unsigned short remove_ushort(const char *propname)
Definition: cfgfile.cpp:318
void clear()
Definition: weakptr.h:120
virtual void printDebugProperties(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: charactr.cpp:748
double apply_damage(double damage, Character *source=nullptr, bool userepsys=true, bool send_damage_packet=false)
Definition: charactr.cpp:1886
static bool RunNoCombatCheck(Network::Client *client)
Definition: guardrgn.cpp:88
void produce(const Core::Vital *pVital, VitalValue &vv, unsigned int amt)
Definition: charactr.cpp:1529
std::string name
Definition: osmod.cpp:943
Items::Item * search_remote_containers(u32 find_serial, bool *isRemoteContainer) const
Definition: charactr.cpp:3996
void check_undamaged()
Clear a Mobile&#39;s ToBeReportable list when all of the following are true: 1) hits are at maximum 2) mo...
Definition: charactr.cpp:1962
unsigned int gold_carried() const
Definition: charactr.cpp:1309
unsigned short layer_to_zone(unsigned short layer)
Definition: charactr.cpp:182
#define UOBJ_ELF_MALE
Definition: objtype.h:130
virtual void apply_raw_damage_hundredths(unsigned int damage, Character *source, bool userepsys=true, bool send_damage_packet=false)
Definition: charactr.cpp:1794
virtual void inform_enteredarea(Character *whoentered)
Definition: charactr.cpp:2983
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
const VitalValue & vital(unsigned vitalid) const
Definition: charactr.h:1061
void change(ENUM flag, bool value)
Definition: uobject.h:115
CharacterSet opponent_of
Definition: charactr.h:829
void send_wornitem_to_inrange(const Character *chr, const Item *item)
Definition: ufunc.cpp:842
void clear_to_be_reportables()
Definition: repsys.cpp:1167
void showarmor() const
Definition: charactr.cpp:2605
Items::Item * wornitem(int layer) const
Definition: charactr.cpp:1332
virtual void refresh_ar()
Definition: charactr.cpp:2484
unsigned numAttributes
Definition: uvars.h:177
unsigned vitalid
Definition: vital.h:38
int call_long(Bscript::BObjectImp *p0)
Definition: syshook.cpp:70
Core::OneShotTask * swing_task
Definition: charactr.h:831
unsigned short carrying_capacity() const
A Mobile&#39;s carrying capacity is (40 + 3.5*STR + chr.carrying_capacity_mod)*ssopt.carrying_capacity_mo...
Definition: charactr.cpp:527
unsigned char severity
Definition: miscrgn.h:70
#define ERROR_PRINT
Definition: logfacility.h:230
double random_double(double f)
Definition: random.cpp:25
void regen_vital(const Core::Vital *)
Definition: charactr.cpp:1567
std::set< unsigned short > tmplzones()
Definition: armor.cpp:195
void produce(unsigned int hamt)
Definition: charactr.h:238
unsigned short zone_name_to_zone(const char *zname)
Definition: charactr.cpp:201
bool can_move(const Items::Item *item) const
Definition: charactr.cpp:1218
WeatherDef * weatherdef
Definition: uvars.h:151
void schedule_executor(UOExecutor *ex)
Definition: scrsched.cpp:662
double armor_zone_chance_sum
Definition: uvars.h:195
const MultiDef & multidef() const
Definition: multis.cpp:69
virtual void printProperties(Clib::StreamWriter &sw) const
Definition: uobject.cpp:245
bool FileExists(const char *filename)
Definition: fileutil.cpp:118
void send_remove_character_to_nearby_cansee(const Character *chr)
Definition: ufunc.cpp:400
std::vector< Core::ItemRef > remote_containers_
Definition: charactr.h:797
void set_privs(const std::string &privlist)
Definition: charactr.cpp:1178
void set(T *ptr)
Definition: refptr.h:276
const ItemDesc & itemdesc() const
Definition: item.cpp:127
u16 last_textcolor() const
Definition: charactr.cpp:4166
bool read(ConfigElem &elem)
Definition: cfgfile.cpp:1015
bool run(int argc, char **argv)
Items::UWeapon * wrestling_weapon
Definition: uvars.h:146
virtual unsigned int weight() const POL_OVERRIDE
A Mobile&#39;s weight is 10 stones + the weight of their equipment.
Definition: charactr.cpp:513
void readAttributesAndVitals(Clib::ConfigElem &elem)
Definition: charactr.cpp:980
void notify_moved(Mobile::Character &whomoved)
Definition: realm.cpp:131
void clear_my_lawful_damagers()
Definition: repsys.cpp:1223
void send_season_info(Client *client)
Definition: ufunc.cpp:2090
bool equippable(const Items::Item *item) const
Definition: charactr.cpp:1356
#define INFO_PRINT
Definition: logfacility.h:223
unsigned short character_slots
Definition: polcfg.h:65
Core::OneShotTask * party_decline_timeout_
Definition: charactr.h:853
void start_script(const char *filename, Bscript::BObjectImp *param0, Bscript::BObjectImp *param1)
Definition: scrsched.cpp:150
virtual std::string name() const
Definition: uobject.cpp:196
virtual u16 get_damaged_sound() const
Definition: charactr.cpp:3205
bool empty() const
Definition: strset.cpp:28
#define pf_endl
Definition: proplist.cpp:25
int current() const
Definition: charactr.h:192
void send_owncreate(Client *client, const Character *chr)
Definition: ufunc.cpp:206
Bscript::BObjectImp * make_mobileref(Mobile::Character *chr)
Definition: mkscrobj.cpp:14
bool has_active_gump() const
Definition: charactr.cpp:459
virtual void unregister_object(UObject *obj)
Definition: multis.cpp:62
void set_stealthsteps(unsigned short newval)
Definition: charactr.cpp:3624
void send_create_mobile_to_nearby_cansee(const Character *chr)
Definition: ufunc.cpp:1895
bool insured() const
Definition: item.h:348
std::string all_settings() const
Definition: charactr.cpp:1168
bool squelched() const
Definition: charactr.cpp:4042
bool check_skill(Core::USKILLID skillid, int difficulty, unsigned short pointvalue)
Definition: charactr.cpp:2626
bool trade_accepted() const
Definition: charactr.cpp:4122
void do_attack_effects(Character *target)
Definition: charactr.cpp:3162
void cancel_trade(Mobile::Character *chr1)
Definition: dropitem.cpp:979
size_t estimatedSize() const
Definition: strset.cpp:77
#define UOBJ_DEATH_ROBE
Definition: objtype.h:217
#define UOBJ_ELF_FEMALE_GHOST
Definition: objtype.h:133
const AttributeValue & weapon_attribute() const
Definition: charactr.cpp:3112
void send_map_difs(Client *client)
Sends number of maps used and number of map/static patches for each map.
Definition: ufunc.cpp:2044
bool layer_is_equipped(int layer) const
Definition: charactr.cpp:1337
Definition: berror.cpp:12
const polclock_t POLCLOCKS_PER_SEC
Definition: polclock.h:29
const unsigned VITAL_MAX_VALUE
Definition: vital.h:55
boost_utils::object_name_flystring name_
Definition: uobject.h:272
const unsigned POLCLASS_NPC
Definition: polclass.h:16
unsigned remove_unsigned(const char *propname)
Definition: cfgfile.cpp:360
bool remove_bool(const char *propname)
Definition: cfgfile.cpp:426
static void tell_vital_changed(Mobile::Character *who, const Core::Vital *vital)
Definition: cliface.cpp:66
enum Pol::Mobile::Character::MOVEREASON move_reason
bool is_at_maximum() const
Definition: charactr.h:201
const unsigned int VITAL_HIGHEST_MAX_HUNDREDTHS
Definition: vital.h:60
unsigned short min_weapon_damage() const
Definition: charactr.cpp:3122
void copyprops(const UObject &obj)
Definition: uobject.cpp:174
std::atomic< bool > exit_signalled
virtual void add(Item *item) POL_OVERRIDE
Definition: corpse.cpp:44
unsigned short projectile_anim() const
Definition: weapon.cpp:389
ExportedFunction * parry_advancement_hook
Definition: syshook.h:71
bool dead() const
Definition: charactr.h:931
bool can_access(const Items::Item *item, int range=-1) const
Definition: charactr.cpp:1201
void set_current(const Core::Vital *pVital, VitalValue &vv, unsigned int ones)
Definition: charactr.cpp:1560
void send_sysmessage(Network::Client *client, const char *text, unsigned short font, unsigned short color)
Definition: ufunc.cpp:1147
void check_light_region_change()
Definition: charactr.cpp:3416
ExportedFunction * check_skill_hook
Definition: syshook.h:67
Account * find_account(const char *acctname)
Definition: accounts.cpp:151
virtual Items::UWeapon * intrinsic_weapon()
Definition: charactr.cpp:1459
bool hidden() const
Definition: charactr.h:941
void update_item_to_inrange(const Item *item)
Definition: ufunc.cpp:737
Module::OSExecutorModule * os_module
Definition: uoexec.h:37
unsigned short speed() const
Definition: weapon.cpp:343
static Attribute * FindAttribute(const std::string &str)
Definition: attribute.cpp:22
std::vector< VitalValue > vitals
Definition: charactr.h:836
bool take_contents_to_grave() const
Definition: corpse.cpp:34
void send_action_to_inrange(const Mobile::Character *obj, UACTION action, unsigned short framecount=0x05, unsigned short repeatcount=0x01, DIRECTION_FLAG_OLD backward=FORWARD, REPEAT_FLAG_OLD repeatflag=NOREPEAT, unsigned char delay=0x01)
Definition: bowsalut.cpp:180
bool can_plogany() const
Definition: charactr.cpp:1261
unsigned short default_cap
Definition: attribute.h:55
bool invul() const
Definition: charactr.cpp:4080
ExportedFunction * hitmiss_hook
Definition: syshook.h:75
virtual void inform_imoved(Character *chr)
Definition: charactr.cpp:2992
UObjCount uobjcount
Definition: state.h:49
u16 intelligence() const
Definition: charactr.cpp:4093
#define INC_PROFILEVAR(counter)
Definition: profile.h:85