Pol  Revision:cb584c9
repsys.cpp
Go to the documentation of this file.
1 
11 #include "repsys.h"
12 
13 #include <stddef.h>
14 #include <string>
15 
16 #include "../clib/cfgelem.h"
17 #include "../clib/cfgfile.h"
18 #include "../clib/cfgsect.h"
19 #include "../clib/logfacility.h"
20 #include "../clib/rawtypes.h"
21 #include "cmbtcfg.h"
22 #include "fnsearch.h"
23 #include "globals/settings.h"
24 #include "globals/state.h"
25 #include "guilds.h"
26 #include "mobile/charactr.h"
27 #include "mobile/npc.h"
28 #include "npctmpl.h"
29 #include "party.h"
30 #include "pktdef.h"
31 #include "polsig.h"
32 #include "repsys_cfg.h"
33 #include "schedule.h"
34 #include "syshook.h"
35 #include "ufunc.h"
36 #include "uworld.h"
37 
38 // BUGS:
39 // it looks like you can restart someone's aggressor timer by toggling war mode and setting
40 // opponent.
41 //
42 
43 namespace Pol
44 {
45 namespace Core
46 {
48 
69 
71 {
79 }
81 {
83  elem.remove_ushort( "CriminalFlagInterval" );
85  elem.remove_ushort( "AggressorFlagTimeout" );
87  elem.remove_bool( "PartyHelpFullCountsAsCriminal", false );
88 }
90 {
91  std::string temp;
92  if ( elem.remove_prop( "NameColor", &temp ) )
94  if ( elem.remove_prop( "HighLightColor", &temp ) )
96  FindExportedFunction( elem, nullptr, temp, 2 );
97 
98  if ( elem.remove_prop( "OnAttack", &temp ) )
99  settingsManager.repsys_cfg.Hooks.OnAttack = FindExportedFunction( elem, nullptr, temp, 2 );
100  if ( elem.remove_prop( "OnDamage", &temp ) )
101  settingsManager.repsys_cfg.Hooks.OnDamage = FindExportedFunction( elem, nullptr, temp, 2 );
102  if ( elem.remove_prop( "OnHelp", &temp ) )
103  settingsManager.repsys_cfg.Hooks.OnHelp = FindExportedFunction( elem, nullptr, temp, 2 );
104 }
105 
107 {
108  if ( settingsManager.repsys_cfg.Hooks.NameColor != nullptr )
109  {
112  }
114  {
117  }
118  if ( settingsManager.repsys_cfg.Hooks.OnAttack != nullptr )
119  {
122  }
123  if ( settingsManager.repsys_cfg.Hooks.OnDamage != nullptr )
124  {
127  }
128  if ( settingsManager.repsys_cfg.Hooks.OnHelp != nullptr )
129  {
132  }
133 }
134 
136 {
138 }
139 
140 void load_repsys_cfg( bool reload )
141 {
142  Clib::ConfigFile cf( "config/repsys.cfg" );
143 
144  Clib::ConfigSection namecoloring( cf, "NameColoring" );
145  Clib::ConfigSection general( cf, "General" );
146  Clib::ConfigSection hooks( cf, "HookList", Clib::CST_NORMAL );
147 
148  Clib::ConfigElem elem;
149 
150  while ( cf.read( elem ) )
151  {
152  if ( namecoloring.matches( elem ) )
153  {
155  }
156  else if ( general.matches( elem ) )
157  {
158  load_repsys_cfg_general( elem );
159  }
160  else if ( hooks.matches( elem ) && !reload )
161  {
162  load_repsys_cfg_hooks( elem );
163  }
164  }
165 }
166 
184 
186 {
187  THREAD_CHECKPOINT( tasks, 1000 );
188  polclock_t now = polclock();
189  bool refreshall = false;
190 
191  // the 'defensive hostiles' are those that are attacking Amy while she's not innocent.
192  // If she's innocent at the end of this, they will break off the attack.
193  THREAD_CHECKPOINT( tasks, 1001 );
194  Mobile::Character::CharacterSet defensive_hostiles;
195  for ( Mobile::Character::CharacterSet::iterator h_itr = amy->opponent_of.begin();
196  h_itr != amy->opponent_of.end(); ++h_itr )
197  {
198  Mobile::Character* hostile_bob = *h_itr;
199  THREAD_CHECKPOINT( tasks, 1002 );
200 
201  if ( !amy->is_innocent_to( hostile_bob ) )
202  {
203  THREAD_CHECKPOINT( tasks, 1003 );
204  defensive_hostiles.insert( hostile_bob );
205  }
206  THREAD_CHECKPOINT( tasks, 1004 );
207  }
208 
209 
210  THREAD_CHECKPOINT( tasks, 1005 );
211  if ( amy->criminal_until_ && timer_expired( amy->criminal_until_, now ) )
212  {
213  amy->criminal_until_ = 0;
214  refreshall = true;
215  }
216 
217  THREAD_CHECKPOINT( tasks, 1006 );
218  polclock_t earliest_timeout;
219 
220  if ( amy->criminal_until_ )
221  earliest_timeout = amy->criminal_until_;
222  else
223  earliest_timeout = now + 5 * 60 * POLCLOCKS_PER_SEC; // 5 minutes, later code will trim
224 
225  THREAD_CHECKPOINT( tasks, 1007 );
226 
227  Mobile::Character::MobileCont::iterator itr;
228  itr = amy->aggressor_to_.begin();
229  while ( itr != amy->aggressor_to_.end() )
230  {
231  THREAD_CHECKPOINT( tasks, 1008 );
232  Mobile::Character::MobileCont::iterator save_itr = itr;
233  ++itr;
234  polclock_t when = ( *save_itr ).second;
235  THREAD_CHECKPOINT( tasks, 1009 );
236  if ( timer_expired( when, now ) )
237  {
238  THREAD_CHECKPOINT( tasks, 1010 );
239  CharacterRef other = ( *save_itr ).first;
240  // not sure if this is right. what if also lawfully_damaged ?
241  THREAD_CHECKPOINT( tasks, 1011 );
242  de_escalate( amy, other.get() );
243  THREAD_CHECKPOINT( tasks, 1012 );
244  amy->aggressor_to_.erase( save_itr );
245  THREAD_CHECKPOINT( tasks, 1013 );
246  if ( !other->orphan() )
247  {
248  // Changed to update!
249  if ( amy->client )
250  send_move( amy->client, amy );
252  }
253  else
254  POLLOG << "NOTE: repsys crash avoidance...\n";
255  THREAD_CHECKPOINT( tasks, 1014 );
256  refreshall = true;
257  }
258  else
259  {
260  earliest_timeout = earliest_timer( when, earliest_timeout );
261  }
262  THREAD_CHECKPOINT( tasks, 1015 );
263  }
264 
265  THREAD_CHECKPOINT( tasks, 1016 );
266  itr = amy->lawfully_damaged_.begin();
267  while ( itr != amy->lawfully_damaged_.end() )
268  {
269  THREAD_CHECKPOINT( tasks, 1017 );
270  Mobile::Character::MobileCont::iterator save_itr = itr;
271  ++itr;
272  polclock_t when = ( *save_itr ).second;
273  THREAD_CHECKPOINT( tasks, 1018 );
274  if ( timer_expired( when, now ) )
275  {
276  THREAD_CHECKPOINT( tasks, 1019 );
277  CharacterRef other = ( *save_itr ).first;
278  // not sure if this is right. what if also aggressor_to ?
279  THREAD_CHECKPOINT( tasks, 1020 );
280  de_escalate( amy, other.get() );
281  THREAD_CHECKPOINT( tasks, 1021 );
282  amy->lawfully_damaged_.erase( save_itr );
283  THREAD_CHECKPOINT( tasks, 1022 );
284  if ( !other->orphan() )
285  {
286  // Changed to update!
287  if ( amy->client )
288  send_move( amy->client, amy );
290  }
291  else
292  POLLOG << "NOTE: repsys crash avoidance...\n";
293  THREAD_CHECKPOINT( tasks, 1023 );
294  refreshall = true;
295  }
296  else
297  {
298  earliest_timeout = earliest_timer( when, earliest_timeout );
299  }
300  THREAD_CHECKPOINT( tasks, 1024 );
301  }
302 
303  THREAD_CHECKPOINT( tasks, 1025 );
304  // For those that were hostile to Amy due to her non-Innocence, if she's Innocent now,
305  // break off the attack.
306  for ( Mobile::Character::CharacterSet::iterator h_itr = defensive_hostiles.begin();
307  h_itr != defensive_hostiles.end(); ++h_itr )
308  {
309  Mobile::Character* bob = *h_itr;
310  THREAD_CHECKPOINT( tasks, 1026 );
311 
312  if ( amy->is_innocent_to( bob ) )
313  {
314  THREAD_CHECKPOINT( tasks, 1027 );
315  de_escalate( amy, bob );
316  THREAD_CHECKPOINT( tasks, 1028 );
317 
318  refreshall = true;
319  }
320  }
321 
322  THREAD_CHECKPOINT( tasks, 1029 );
323 
324  if ( amy->criminal_until_ || !amy->aggressor_to_.empty() || !amy->lawfully_damaged_.empty() )
325  {
326  THREAD_CHECKPOINT( tasks, 1030 );
327  schedule_repsys_task( amy, earliest_timeout + 1 );
328  }
329 
330  THREAD_CHECKPOINT( tasks, 1031 );
331  if ( refreshall )
332  {
333  THREAD_CHECKPOINT( tasks, 1032 );
334  if ( !amy->orphan() )
335  {
336  // Changed to update!
337  if ( amy->client )
338  send_move( amy->client, amy );
340  }
341  }
342  THREAD_CHECKPOINT( tasks, 1099 );
343 }
344 
345 
347 {
348  if ( chr->repsys_task_ != nullptr )
349  {
350  if ( chr->repsys_task_->next_run_clock() > runat )
351  chr->repsys_task_->cancel();
352  }
353 
354  if ( chr->repsys_task_ == nullptr )
355  {
357  chr );
358  }
359 }
360 bool private_say_above_ex( Mobile::Character* chr, const UObject* obj, const char* text,
361  unsigned short color );
362 // bool RepSystem::can_attack( Character* attacker, Character* defender )
363 // {
364 // return (defender->is_aggressor_to( attacker ) ||
365 // attacker->has_lawfully_damaged(defender) ||
366 // defender->is_criminal());
367 // }
368 //
369 
370 // a scenario:
371 // A (innocent) attacks B (innocent):
372 // (3), so A criminal, aggressor to B
373 // A (crim,agg) attacks B (innocent):
374 // (1), so A's aggressor timer restarts (not criminal timer)
375 // B (innocent) attacks A (crim,agg):
376 // (2b), so lawfully damaged timer restarts
377 // B (innocent) attacks A (crim,agg):
378 // (2a), so lawfully damaged timer restarts
379 // A (crim, agg) attacks B (innocent):
380 // umm, what should happen?
381 
382 
407 
409 {
410  if ( amy_attacker == bob_defender )
411  return;
412 
413  bool refresh = false;
414 
415  polclock_t now = polclock();
416  polclock_t crim_timeout_at =
418  polclock_t aggr_timeout_at =
420 
421  if ( bob_defender->is_innocent_to( amy_attacker ) )
422  {
423  if ( !amy_attacker->is_criminal() )
424  refresh = true;
425  amy_attacker->restart_criminal_timer( crim_timeout_at );
426  }
427 
428  if ( bob_defender->is_aggressor_to( amy_attacker ) )
429  {
430  bob_defender->restart_aggressor_timer( amy_attacker, aggr_timeout_at );
431  }
432  else // he's not the aggressor, so I guess I am.
433  {
434  if ( !amy_attacker->is_aggressor_to( bob_defender ) )
435  {
437  {
438  std::string msg = "*" + amy_attacker->name() + " is attacking you!*";
439  private_say_above_ex( bob_defender, bob_defender, msg.c_str(),
441  }
442  refresh = true;
443  }
444  amy_attacker->restart_aggressor_timer( bob_defender, aggr_timeout_at );
445  }
446 
447  if ( refresh )
448  {
449  // Changed to update!
450  if ( amy_attacker->client )
451  send_move( amy_attacker->client, amy_attacker );
452  send_create_mobile_to_nearby_cansee( amy_attacker );
453  }
454  polclock_t timeout_at = earliest_timer( crim_timeout_at, aggr_timeout_at );
455 
456  schedule_repsys_task( amy_attacker, timeout_at + 1 );
457  schedule_repsys_task( bob_defender, timeout_at + 1 );
458 }
459 
480 {
481  if ( amy == bob )
482  return;
483  polclock_t aggr_timeout_at =
485 
486  on_pc_attacks_pc( amy, bob );
487 
488  if ( bob->is_innocent_to( amy ) )
489  {
490  bob->add_to_be_reportable( amy->serial );
491  }
492  else
493  {
494  amy->restart_lawfully_damaged_timer( bob, aggr_timeout_at );
495  schedule_repsys_task( amy, aggr_timeout_at + 1 );
496  }
497 }
498 
499 
512 
514 {
515  if ( ( amy != bob ) && bob->is_criminal() )
516  {
518  {
519  Party* party = amy->party();
520  if ( ( party != nullptr ) && ( party->is_member( bob->serial ) ) )
521  return;
522  }
523  amy->make_criminal();
524  }
525 }
526 
532 
534 {
535  if ( amy->opponent_ == bob )
536  {
537  amy->set_opponent( nullptr, true );
538  }
539 
540  if ( bob->opponent_ == amy )
541  {
542  bob->set_opponent( nullptr, true );
543  }
544 }
545 
558 
560  const Mobile::Character* bob )
561 {
563  {
564  Mobile::Character* t_amy = const_cast<Mobile::Character*>( amy );
565  Mobile::Character* t_bob = const_cast<Mobile::Character*>( bob );
567  t_bob->make_ref(), t_amy->make_ref() );
568  if ( hook_highlight != -1 )
569  return (unsigned char)hook_highlight;
570  }
571 
572  if ( ( settingsManager.ssopt.invul_tag == 2 ) && bob->invul() )
573  return CHAR_HILITE_INVUL;
574  if ( bob->is_murderer() )
575  return CHAR_HILITE_MURDERER;
576  if ( bob->is_criminal() )
577  return CHAR_HILITE_CRIMINAL;
578  if ( bob->is_guild_ally( amy ) )
579  return CHAR_HILITE_FRIEND;
580  if ( bob->is_aggressor_to( amy ) || amy->has_lawfully_damaged( bob ) )
581  return CHAR_HILITE_ATTACKABLE;
582  if ( bob->is_guild_enemy( amy ) )
583  return CHAR_HILITE_ENEMY;
584 
585  return CHAR_HILITE_INNOCENT;
586 }
587 
588 /*
589  * AMY = Mobile doing the seeing
590  * BOB = Mobile being seen.
591  *
592  */
593 unsigned short RepSystem::name_color( const Mobile::Character* amy, const Mobile::Character* bob )
594 {
596  {
597  Mobile::Character* t_amy = const_cast<Mobile::Character*>( amy );
598  Mobile::Character* t_bob = const_cast<Mobile::Character*>( bob );
599  int hook_color = settingsManager.repsys_cfg.Hooks.NameColor->call_long( t_bob->make_ref(),
600  t_amy->make_ref() );
601  if ( hook_color != -1 )
602  return (unsigned short)hook_color;
603  }
604 
605  if ( settingsManager.ssopt.invul_tag == 2 )
606  {
607  if ( bob->invul() )
609  }
610  if ( bob->is_murderer() )
612  if ( bob->is_criminal() )
614  else if ( bob->is_guild_ally( amy ) )
616  else if ( bob->is_aggressor_to( amy ) || amy->has_lawfully_damaged( bob ) )
618  else if ( bob->is_guild_enemy( amy ) )
620  else
622 }
623 } // namespace Core
624 namespace Mobile
625 {
638 bool Character::is_innocent_to( const Character* amy ) const
639 {
640  // this == bob
641  const Character& bob = *this;
642 
643  if ( bob.is_murderer() )
644  return false;
645 
646  if ( bob.is_criminal() )
647  return false;
648 
649  if ( bob.is_aggressor_to( amy ) )
650  return false;
651 
652  if ( bob.is_guild_ally( amy ) )
653  return false;
654 
655  if ( bob.is_guild_enemy( amy ) )
656  return false;
657 
658  if ( amy->has_lawfully_damaged( &bob ) )
659  return false;
660 
661  return true;
662 }
663 
664 bool Character::is_aggressor_to( const Character* chr ) const
665 {
666  Character* in_chr = const_cast<Character*>( chr );
667  return ( aggressor_to_.find( Core::CharacterRef( in_chr ) ) != aggressor_to_.end() );
668 }
669 
680 bool Character::is_guild_ally( const Character* chr ) const
681 {
682  auto thisguild = guild();
683  auto otherguild = chr->guild();
684  return ( thisguild != nullptr && otherguild != nullptr &&
685  Core::Guild::AreAllies( thisguild, otherguild ) );
686 }
687 
696 bool Character::is_guild_enemy( const Character* chr ) const
697 {
698  auto thisguild = guild();
699  auto otherguild = chr->guild();
700  return ( thisguild != nullptr && otherguild != nullptr &&
701  Core::Guild::AreEnemies( thisguild, otherguild ) );
702 }
703 
704 //
705 // To Mark Bob an Aggressor to Amy:
706 // Bob is reported as an Aggressor to Amy for 2 minutes
707 //
708 //
710 {
711  MobileCont::iterator itr = aggressor_to_.find( Core::CharacterRef( amy ) );
712  if ( itr == aggressor_to_.end() )
713  {
714  aggressor_to_[Core::CharacterRef( amy )] = until;
715  }
716  else
717  {
718  if ( until > ( *itr ).second )
719  ( *itr ).second = until;
720  }
721 }
722 
724 {
725  Character* in_chr = const_cast<Character*>( chr );
726  return ( lawfully_damaged_.find( Core::CharacterRef( in_chr ) ) != lawfully_damaged_.end() );
727 }
728 
730 {
731  MobileCont::iterator itr = lawfully_damaged_.find( Core::CharacterRef( amy ) );
732  if ( itr == lawfully_damaged_.end() )
733  {
734  lawfully_damaged_[Core::CharacterRef( amy )] = when;
735  }
736  else
737  {
738  if ( when > ( *itr ).second )
739  ( *itr ).second = when;
740  }
741 }
742 
750 {
751  return is_temporally_criminal() || is_murderer();
752 }
754 {
755  return ( Core::polclock() <= criminal_until_ );
756 }
757 
759 {
760  if ( until > criminal_until_ )
761  {
762  if ( criminal_until_ < Core::polclock() )
763  {
765  x, y, realm, 32, [&]( Character* chr ) { NpcPropagateCriminal( chr, this ); } );
766  }
767  criminal_until_ = until;
768  }
769 }
770 
772 {
773  criminal_until_ = 0;
774 }
775 
777 {
778  return mob_flags_.get( MOB_FLAGS::MURDERER );
779 }
780 
781 
782 //
783 // Everything below this point is DOUBLE-DISPATCH for
784 // PC vs NPC, NPC vs PC, NPC vs NPC
785 // as well as PC -> NPC reactions.
786 //
787 
788 /* the reputation system only comes into play if:
789  a player attacks a player
790  a player attacks a player's creature
791  a player's creature attacks a player
792  a player's creature attacks a player's creature
793  */
794 
795 
810 {
811  if ( Core::settingsManager.repsys_cfg.Hooks.OnAttack )
812  {
813  if ( Core::settingsManager.repsys_cfg.Hooks.OnAttack->call( this->make_ref(),
814  defender->make_ref() ) )
815  return;
816  }
817 
818  // consider double-dispatch here.
819  if ( defender->isa( Core::UOBJ_CLASS::CLASS_CHARACTER ) )
820  {
821  Core::RepSystem::on_pc_attacks_pc( this, defender );
822  }
823  else
824  {
825  NPC* npc = static_cast<NPC*>( defender );
826  if ( npc->master() )
827  {
829  }
830  else if ( ( npc->alignment() == Core::NpcTemplate::GOOD ) && ( !npc->is_criminal() ) )
831  {
832  make_criminal();
833  }
834  }
835 }
836 
845 {
846  if ( Core::settingsManager.repsys_cfg.Hooks.OnAttack )
847  {
848  if ( Core::settingsManager.repsys_cfg.Hooks.OnAttack->call( this->make_ref(),
849  defender->make_ref() ) )
850  return;
851  }
852 
853  if ( master() )
854  {
855  master_->Character::repsys_on_attack( defender );
856  }
857 }
858 
873 {
874  if ( Core::settingsManager.repsys_cfg.Hooks.OnDamage )
875  {
876  if ( Core::settingsManager.repsys_cfg.Hooks.OnDamage->call( this->make_ref(),
877  defender->make_ref() ) )
878  return;
879  }
880 
881  if ( defender->isa( Core::UOBJ_CLASS::CLASS_CHARACTER ) )
882  {
883  Core::RepSystem::on_pc_damages_pc( this, defender );
884  }
885  else
886  {
887  NPC* npc = static_cast<NPC*>( defender );
888  if ( npc->master() )
889  {
891  }
892  else if ( ( npc->alignment() == Core::NpcTemplate::GOOD ) && ( !npc->is_criminal() ) )
893  {
894  make_criminal();
895  }
896  }
897 }
898 
907 {
908  if ( Core::settingsManager.repsys_cfg.Hooks.OnDamage )
909  {
910  if ( Core::settingsManager.repsys_cfg.Hooks.OnDamage->call( this->make_ref(),
911  defender->make_ref() ) )
912  return;
913  }
914 
915  if ( master() )
916  master_->Character::repsys_on_damage( defender );
917 }
918 
931 
933 {
934  if ( Core::settingsManager.repsys_cfg.Hooks.OnHelp )
935  {
936  if ( Core::settingsManager.repsys_cfg.Hooks.OnHelp->call( this->make_ref(),
937  helped->make_ref() ) )
938  return;
939  }
940 
941  // repsys_on_pc_helps( helped );
942  if ( helped->isa( Core::UOBJ_CLASS::CLASS_CHARACTER ) )
943  {
944  Core::RepSystem::on_pc_helps_pc( this, helped );
945  }
946  else
947  {
948  NPC* npc = static_cast<NPC*>( helped );
949  if ( npc->master() )
950  {
951  Core::RepSystem::on_pc_helps_pc( this, npc->master() );
952  }
953  else if ( npc->alignment() == Core::NpcTemplate::EVIL )
954  {
955  make_criminal();
956  }
957  }
958 }
959 
968 {
969  if ( Core::settingsManager.repsys_cfg.Hooks.OnHelp )
970  {
971  if ( Core::settingsManager.repsys_cfg.Hooks.OnHelp->call( this->make_ref(),
972  helped->make_ref() ) )
973  return;
974  }
975 
976  // repsys_on_npc_helps( helped );
977  if ( master() )
978  master_->Character::repsys_on_help( helped );
979 }
980 
981 unsigned char Character::hilite_color_idx( const Character* seen_by ) const
982 {
983  return Core::RepSystem::hilite_color_idx( seen_by, this );
984 }
985 unsigned short Character::name_color( const Character* seen_by ) const
986 {
987  return Core::RepSystem::name_color( seen_by, this );
988 }
989 
1001 unsigned char NPC::hilite_color_idx( const Character* seen_by ) const
1002 {
1003  if ( Core::settingsManager.repsys_cfg.Hooks.HighLightColor )
1004  {
1005  NPC* t_amy = const_cast<NPC*>( this );
1006  Character* t_bob = const_cast<Character*>( seen_by );
1008  t_amy->make_ref(), t_bob->make_ref() );
1009  if ( hook_highlight != -1 )
1010  return (unsigned char)( hook_highlight );
1011  }
1012 
1013  if ( Core::settingsManager.ssopt.invul_tag == 2 )
1014  {
1015  if ( invul() )
1016  return CHAR_HILITE_INVUL;
1017  }
1018  if ( master() )
1019  {
1020  return Core::RepSystem::hilite_color_idx( seen_by, master() );
1021  }
1022  else
1023  {
1024  switch ( template_.alignment )
1025  {
1027  return CHAR_HILITE_ATTACKABLE;
1029  if ( is_murderer() )
1030  return CHAR_HILITE_MURDERER;
1031  else if ( is_criminal() )
1032  return CHAR_HILITE_ATTACKABLE;
1033  else
1034  return CHAR_HILITE_INNOCENT;
1036  return CHAR_HILITE_MURDERER;
1037  }
1038  return CHAR_HILITE_ATTACKABLE;
1039  }
1040 }
1041 
1042 unsigned short NPC::name_color( const Character* seen_by ) const
1043 {
1044  if ( Core::settingsManager.repsys_cfg.Hooks.NameColor )
1045  {
1046  NPC* t_amy = const_cast<NPC*>( this );
1047  Character* t_bob = const_cast<Character*>( seen_by );
1049  t_amy->make_ref(), t_bob->make_ref() );
1050  if ( hook_color != -1 )
1051  return (unsigned short)hook_color;
1052  }
1053 
1054  if ( Core::settingsManager.ssopt.invul_tag == 2 )
1055  {
1056  if ( this->invul() )
1057  return Core::settingsManager.repsys_cfg.NameColoring.Invulnerable;
1058  }
1059  if ( master() )
1060  {
1061  return Core::RepSystem::name_color( seen_by, master() );
1062  }
1063  else
1064  {
1065  switch ( template_.alignment )
1066  {
1070  if ( is_murderer() )
1072  else if ( is_criminal() )
1074  else
1078  }
1079 
1081  }
1082 }
1083 
1092 
1093 void Character::make_criminal( int level )
1094 {
1095  set_dirty();
1096  bool was_criminal = is_criminal();
1097 
1098  if ( level )
1099  {
1100  Core::polclock_t timeout_at =
1103 
1104  restart_criminal_timer( timeout_at );
1105  Core::RepSystem::schedule_repsys_task( this, timeout_at + 1 );
1106  }
1107  else
1108  {
1109  clear_criminal_timer();
1111  }
1112 
1113  if ( !orphan() && was_criminal != is_criminal() )
1114  {
1115  // Changed to update!
1116  on_criminal_changed();
1117  }
1118 }
1119 
1120 void Character::make_murderer( bool newval )
1121 {
1122  bool refresh = ( mob_flags_.get( MOB_FLAGS::MURDERER ) != newval );
1123 
1124  set_dirty();
1125  mob_flags_.change( MOB_FLAGS::MURDERER, newval );
1126 
1127  if ( !orphan() && refresh )
1128  {
1129  // Changed to update!
1130  on_murderer_changed();
1131  }
1133 }
1134 
1136 {
1137  Core::polclock_t aggr_timeout_at =
1138  Core::polclock() +
1140  restart_aggressor_timer( chr, aggr_timeout_at );
1141 
1142  // Changed to update!
1143  on_aggressor_changed();
1144 
1145  Core::RepSystem::schedule_repsys_task( this, aggr_timeout_at + 1 );
1146 }
1147 
1149 {
1150  Core::polclock_t aggr_timeout_at =
1151  Core::polclock() +
1153  restart_lawfully_damaged_timer( chr, aggr_timeout_at );
1154 
1155  // Changed to update!
1156  on_lawfullydamaged_changed();
1157 
1158  Core::RepSystem::schedule_repsys_task( this, aggr_timeout_at + 1 );
1159 }
1160 
1161 // add serial to Bob's ToBeReportable list
1163 {
1164  set_dirty();
1165  to_be_reportable_.insert( repserial );
1166 }
1168 {
1169  set_dirty();
1170  to_be_reportable_.clear();
1171 }
1173 {
1174  set_dirty();
1176 
1177  ToBeReportableList::iterator itr = to_be_reportable_.begin(), end = to_be_reportable_.end();
1178  for ( ; itr != end; ++itr )
1179  {
1180  reportable_t rt;
1181  rt.serial = ( *itr );
1182  rt.polclock = now;
1183  reportable_.insert( rt );
1184  }
1185 
1186  to_be_reportable_.clear();
1187 }
1189 {
1190  set_dirty();
1191  reportable_t rt;
1192  rt.serial = repserial;
1193  rt.polclock = when;
1194  reportable_.erase( rt );
1195 }
1197 {
1198  // we don't actually have a list of aggressors.
1199  ToBeReportableList::iterator itr = to_be_reportable_.begin(), end = to_be_reportable_.end();
1200  for ( ; itr != end; ++itr )
1201  {
1202  u32 repserial = ( *itr );
1203  Character* aggressor = Core::system_find_mobile( repserial );
1204  if ( aggressor != nullptr )
1205  {
1206  aggressor->remove_as_aggressor_to( this );
1207  }
1208  }
1209 }
1211 {
1212  Core::CharacterRef ref( chr );
1213  aggressor_to_.erase( ref );
1214  if ( chr->client != nullptr )
1215  {
1217  }
1218  if ( client != nullptr )
1219  {
1220  send_create_mobile_if_nearby_cansee( client, chr );
1221  }
1222 }
1224 {
1225  // we don't actually have a list of aggressors.
1226  ToBeReportableList::iterator itr = to_be_reportable_.begin(), end = to_be_reportable_.end();
1227  for ( ; itr != end; ++itr )
1228  {
1229  u32 repserial = ( *itr );
1230  Character* damager = Core::system_find_mobile( repserial );
1231  if ( damager != nullptr )
1232  {
1233  damager->remove_as_lawful_damager( this );
1234  }
1235  }
1236 }
1237 
1239 {
1240  Core::CharacterRef ref( chr );
1241  lawfully_damaged_.erase( ref );
1242 
1243  if ( chr->client != nullptr )
1244  {
1246  }
1247  if ( client != nullptr )
1248  {
1249  send_create_mobile_if_nearby_cansee( client, chr );
1250  }
1251 }
1252 
1253 // Keep these as separate functions if there will be in the future something specific for them
1254 // For now they are just copies of each other
1255 
1257 {
1258  if ( this->client )
1259  send_move( this->client, this );
1261 }
1262 
1264 {
1265  if ( this->client )
1266  send_move( this->client, this );
1268 }
1269 
1271 {
1272  if ( this->client )
1273  send_move( this->client, this );
1275 }
1276 
1278 {
1279  if ( this->client )
1280  send_move( this->client, this );
1282 }
1283 } // namespace Mobile
1284 } // namespace Pol
static void repsys_task(Mobile::Character *chr)
[2] Timeouts When Any of Amy&#39;s Rep-system timers time out
Definition: repsys.cpp:185
unsigned short Invulnerable
Definition: repsys_cfg.h:26
void load_repsys_cfg_general(Clib::ConfigElem &elem)
Definition: repsys.cpp:80
Character * opponent_
Definition: charactr.h:828
struct Pol::Core::RepSys_Cfg::@56 General
unsigned short GuildEnemy
Definition: repsys_cfg.h:25
void on_lawfullydamaged_changed()
Definition: repsys.cpp:1277
ExportedFunction * HighLightColor
Definition: repsys_cfg.h:39
bool is_criminal() const
A Mobile is Criminal if: he has an active Criminal Timer, which has not timed out. OR he is a murderer.
Definition: repsys.cpp:749
bool is_murderer() const
Definition: repsys.cpp:776
void add_to_be_reportable(u32 serial)
Definition: repsys.cpp:1162
void set_opponent(Character *opponent, bool inform_old_opponent=true)
Definition: charactr.cpp:2994
unsigned short Innocent
Definition: repsys_cfg.h:23
#define CHAR_HILITE_ATTACKABLE
Definition: pktdef.h:57
Character * master() const
Definition: npc.h:265
Network::Client * client
Definition: charactr.h:871
static void on_pc_attacks_pc(Mobile::Character *attacker, Mobile::Character *defender)
[3] Player attacks another Player When Amy attacks Bob These rules are applied:
Definition: repsys.cpp:408
polclock_t polclock()
Definition: polclock.cpp:72
polclock_t earliest_timer(polclock_t timer1_until, polclock_t timer2_until)
Definition: polclock.h:43
void make_lawfullydamaged_to(Character *chr)
Definition: repsys.cpp:1148
static bool AreAllies(Guild *g1, Guild *g2)
Definition: guilds.cpp:178
MobileCont lawfully_damaged_
Definition: charactr.h:844
ExportedFunction * OnHelp
Definition: repsys_cfg.h:42
void clear_reportable(u32 serial, Core::polclock_t time)
Definition: repsys.cpp:1188
void restart_criminal_timer(Core::polclock_t until)
Definition: repsys.cpp:758
void unload_repsys_cfg()
Definition: repsys.cpp:135
unsigned short Criminal
Definition: repsys_cfg.h:21
static void on_pc_helps_pc(Mobile::Character *helper, Mobile::Character *helped)
[5] Player Helps Another Player When Amy Helps Bob These rules applied:
Definition: repsys.cpp:513
Core::polclock_t polclock
Definition: charactr.h:276
static bool AreEnemies(Guild *g1, Guild *g2)
Definition: guilds.cpp:182
unsigned short AggressorFlagTimeout
Definition: repsys_cfg.h:32
virtual void repsys_on_help(Character *recipient)
[15] Mobile (MA) Helps Mobile (MB)
Definition: repsys.cpp:932
unsigned short Attackable
Definition: repsys_cfg.h:22
bool private_say_above_ex(Mobile::Character *chr, const UObject *obj, const char *text, unsigned short color)
Definition: ufunc.cpp:1400
bool PartyHelpFullCountsAsCriminal
Definition: repsys_cfg.h:33
bool is_member(u32 serial) const
Definition: party.cpp:281
#define THREAD_CHECKPOINT(thread, check)
Definition: polsig.h:48
virtual unsigned char hilite_color_idx(const Character *seen_by) const POL_OVERRIDE
[16] NPC Highlighting If the NPC has a master, Highlight color is the same as the Master&#39;s...
Definition: repsys.cpp:1001
virtual void repsys_on_damage(Character *defender)
[14] Mobile (MA) Damages Mobile (MB)
Definition: repsys.cpp:872
ExportedFunction * OnAttack
Definition: repsys_cfg.h:40
void send_create_mobile_if_nearby_cansee(Client *client, const Character *chr)
Definition: ufunc.cpp:1886
static void InRange(u16 x, u16 y, const Realms::Realm *realm, unsigned range, F &&f)
Definition: uworld.h:235
bool matches(const ConfigElem &elem)
Definition: cfgsect.cpp:32
virtual void repsys_on_help(Character *recipient) POL_OVERRIDE
[15.2] NPC (MA) Helps Mobile (MB) If MA has a Master (Amy), Apply &#39;Player Helps Mobile&#39; rules[->15...
Definition: repsys.cpp:967
virtual unsigned short name_color(const Character *seen_by) const
Definition: repsys.cpp:985
struct Pol::Core::RepSys_Cfg::@57 Hooks
void load_repsys_cfg_hooks(Clib::ConfigElem &elem)
Definition: repsys.cpp:89
bool is_aggressor_to(const Character *chr) const
Definition: repsys.cpp:664
#define CHAR_HILITE_FRIEND
Definition: pktdef.h:56
void load_repsys_cfg_namecoloring(Clib::ConfigElem &elem)
Reputation System.
Definition: repsys.cpp:70
void make_aggressor_to(Character *chr)
Definition: repsys.cpp:1135
virtual void repsys_on_damage(Character *defender) POL_OVERRIDE
[14.2] NPC (MA) Damages Mobile (MB) If MA has a Master (Amy), Apply &#39;Player Damages Mobile&#39; rules[->1...
Definition: repsys.cpp:906
MobileCont aggressor_to_
Definition: charactr.h:843
unsigned int u32
Definition: rawtypes.h:27
void restart_lawfully_damaged_timer(Character *chr, Core::polclock_t until)
Definition: repsys.cpp:729
bool is_guild_enemy(const Character *chr) const
[10.2] Guild Enemies Bob and Amy are Guild Enemies if: Bob is in a guild, AND Amy is in a guild...
Definition: repsys.cpp:696
#define CHAR_HILITE_CRIMINAL
Definition: pktdef.h:58
virtual void repsys_on_attack(Character *defender)
[13] Mobile (MA) Attacks Mobile (MA)
Definition: repsys.cpp:809
void send_move(Client *client, const Character *chr)
Definition: ufunc.cpp:174
void remove_as_lawful_damager(Character *chr)
Definition: repsys.cpp:1238
virtual void cancel(void) POL_OVERRIDE
Definition: schedule.cpp:143
const unsigned CST_NORMAL
Definition: cfgsect.h:19
polclock_t next_run_clock() const
Definition: schedule.h:66
bool is_temporally_criminal() const
Definition: repsys.cpp:753
virtual unsigned short name_color(const Character *seen_by) const POL_OVERRIDE
Definition: repsys.cpp:1042
#define CHAR_HILITE_INNOCENT
Definition: pktdef.h:55
Core::OneShotTask * repsys_task_
Definition: charactr.h:846
bool orphan() const
Definition: baseobject.h:119
#define CHAR_HILITE_MURDERER
Definition: pktdef.h:60
ref_ptr< Mobile::Character > CharacterRef
Definition: reftypes.h:42
void unload_repsys_cfg_hooks()
Definition: repsys.cpp:106
ExportedFunction * OnDamage
Definition: repsys_cfg.h:41
virtual unsigned char hilite_color_idx(const Character *seen_by) const
Definition: repsys.cpp:981
#define CHAR_HILITE_ENEMY
Definition: pktdef.h:59
void restart_aggressor_timer(Character *chr, Core::polclock_t until)
Definition: repsys.cpp:709
virtual Bscript::BObjectImp * make_ref() POL_OVERRIDE
Definition: uoscrobj.cpp:1650
void load_repsys_cfg(bool reload)
Definition: repsys.cpp:140
#define POLLOG
Definition: logfacility.h:219
int polclock_t
Definition: polclock.h:26
#define CHAR_HILITE_INVUL
Definition: pktdef.h:61
bool has_lawfully_damaged(const Character *chr) const
Definition: repsys.cpp:723
unsigned short invul_tag
Definition: ssopt.h:56
static void de_escalate(Mobile::Character *amy, Mobile::Character *bob)
[7] De-Escalation To De-escalate Amy and Bob: if Amy&#39;s opponent is Bob, Amy clears her opponent If Bo...
Definition: repsys.cpp:533
SettingsManager settingsManager
Definition: settings.cpp:14
void make_murderer(bool newlval=true)
Definition: repsys.cpp:1120
void commit_to_reportables()
Definition: repsys.cpp:1172
static unsigned char hilite_color_idx(const Mobile::Character *chr, const Mobile::Character *who)
[8] Highlighting and Name Coloring if Amy looks at Bob, coloring is as follows: if Bob is invul and i...
Definition: repsys.cpp:559
Mobile::Character * system_find_mobile(u32 serial)
Definition: fnsearch.cpp:32
bool is_innocent_to(const Character *chr) const
[9] Innocent Status Bob is Innocent to Amy if: Bob is Innocent to Amy only if NONE of the following a...
Definition: repsys.cpp:638
unsigned short GuildAlly
Definition: repsys_cfg.h:24
bool remove_prop(const char *propname, std::string *value)
Definition: cfgfile.cpp:128
CombatConfig combat_config
Definition: settings.h:28
std::set< Character * > CharacterSet
Definition: charactr.h:338
void NpcPropagateCriminal(Character *chr, Character *thecriminal)
Definition: charactr.h:1082
Core::polclock_t criminal_until_
Definition: charactr.h:845
void make_criminal(int level=1)
To Set Amy Criminal (For a LevelOfOffense)
Definition: repsys.cpp:1093
static unsigned short name_color(const Mobile::Character *seen_by, const Mobile::Character *who)
Definition: repsys.cpp:593
unsigned short CriminalFlagInterval
Definition: repsys_cfg.h:31
static void schedule_repsys_task(Mobile::Character *chr, polclock_t runat)
Definition: repsys.cpp:346
unsigned short remove_ushort(const char *propname)
Definition: cfgfile.cpp:318
ExportedFunction * FindExportedFunction(Clib::ConfigElem &elem, const Plib::Package *pkg, const std::string &descriptor, unsigned nargs, bool complain_if_missing)
Definition: syshook.cpp:344
void clear_criminal_timer()
Definition: repsys.cpp:771
void remove_as_aggressor_to(Character *chr)
Definition: repsys.cpp:1210
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
CharacterSet opponent_of
Definition: charactr.h:829
void clear_to_be_reportables()
Definition: repsys.cpp:1167
int call_long(Bscript::BObjectImp *p0)
Definition: syshook.cpp:70
ExportedFunction * NameColor
Definition: repsys_cfg.h:38
struct Pol::Core::RepSys_Cfg::@55 NameColoring
static void on_pc_damages_pc(Mobile::Character *attacker, Mobile::Character *defender)
[4] Player Damages Player When Amy damages Bob These rules applied:
Definition: repsys.cpp:479
bool read(ConfigElem &elem)
Definition: cfgfile.cpp:1015
bool timer_expired(polclock_t timer_until, polclock_t now)
Definition: polclock.h:38
void clear_my_lawful_damagers()
Definition: repsys.cpp:1223
virtual std::string name() const
Definition: uobject.cpp:196
void send_create_mobile_to_nearby_cansee(const Character *chr)
Definition: ufunc.cpp:1895
Core::NpcTemplate::ALIGNMENT alignment() const
Definition: npc.h:270
bool is_guild_ally(const Character *chr) const
[10] Guild Rules The following Guild Rules are only temporary pending a more complete system ...
Definition: repsys.cpp:680
Definition: berror.cpp:12
unsigned short Murderer
Definition: repsys_cfg.h:20
const polclock_t POLCLOCKS_PER_SEC
Definition: polclock.h:29
bool remove_bool(const char *propname)
Definition: cfgfile.cpp:426
virtual void repsys_on_attack(Character *defender) POL_OVERRIDE
[13.2] NPC (MA) Attacks Mobile (MB) If MA has a Master (Amy), Apply &#39;Player Attacks Mobile&#39; rules[->1...
Definition: repsys.cpp:844
bool invul() const
Definition: charactr.cpp:4080