Crossfire Server, Trunk
living.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
22 #include <assert.h>
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "global.h"
28 #include "sproto.h"
29 #include "living.h"
30 
31 static float get_con_bonus(int stat);
32 static float get_sp_bonus(int stat);
33 static float get_grace_bonus(int stat);
34 static size_t get_index(int stat, size_t max_index);
35 
41 #define ADD_EXP(exptotal, exp) do { exptotal += exp; if (exptotal > MAX_EXPERIENCE) exptotal = MAX_EXPERIENCE; } while (0)
42 #define ADD_TOTALEXP(exptotal, exp) do { exptotal += exp; if (exptotal > MAX_TOTAL_EXPERIENCE) exptotal = MAX_TOTAL_EXPERIENCE; } while(0)
43 
58 #define INT_FEAR_BONUS 0
59 #define INT_TURN_BONUS 1
60 #define INT_CLERIC_CHANCE 2
61 #define INT_LEARN_SPELL 3
62 #define INT_CHA_BONUS 4
63 #define INT_DEX_BONUS 5
64 #define INT_DAM_BONUS 6
65 #define INT_THAC0_BONUS 7
66 #define INT_WEIGHT_LIMIT 8
67 #define NUM_INT_BONUSES 9
68 
70 
75 static const char *int_bonus_names[NUM_INT_BONUSES] = {
76  "cha_fear_bonus", "wis_turn_bonus", "wis_cleric_chance", "int_wis_learn_spell",
77  "cha_shop_bonus", "dex_bonus", "str_damage_bonus", "str_hit_bonus",
78  "str_weight_limit",
79 };
80 
85 #define FLOAT_CON_BONUS 0
86 #define FLOAT_DEX_BONUS 1
87 #define FLOAT_SP_BONUS 2
88 #define FLOAT_GRACE_BONUS 3
89 #define NUM_FLOAT_BONUSES 4
91 static const char *float_bonus_names[NUM_FLOAT_BONUSES] = {
92  "con_hp_bonus", "dex_speed_bonus", "pow_int_sp_bonus", "wis_pow_grace_bonus"
93 };
94 
95 /*
96  * Since this is nowhere defined ...
97  * Both come in handy at least in function add_exp()
98  */
99 #define MAX_EXPERIENCE levels[settings.max_level]
100 
101 extern int64_t *levels;
102 
103 #define MAX_SAVE_LEVEL 110
104 
113 static const int savethrow[MAX_SAVE_LEVEL+1] = {
114  18,
115  18, 17, 16, 15, 14, 14, 13, 13, 12, 12,
116  12, 11, 11, 11, 11, 10, 10, 10, 10, 9,
117  9, 9, 9, 9, 8, 8, 8, 8, 8, 8,
118  7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
119  6, 6, 6, 6, 6, 5, 5, 5, 5, 5,
120  5, 5, 5, 5, 4, 4, 4, 4, 4, 4,
121  4, 4, 4, 4, 3, 3, 3, 3, 3, 3,
122  3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
123  2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
124  1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
125  1, 1, 1, 1, 1, 1, 1, 1, 1, 1
126 };
127 
129 const char *const attacks[NROFATTACKS] = {
130  "physical", "magical", "fire", "electricity", "cold",
131  "confusion", "acid", "drain", "weaponmagic", "ghosthit",
132  "poison", "slow", "paralyze", "turn undead", "fear",
133  "cancellation", "depletion", "death", "chaos", "counterspell",
134  "god power", "holy power", "blinding", "", "life stealing",
135  "disease"
136 };
137 
139 const char *const drain_msg[NUM_STATS] = {
140  "You feel drained of strength.",
141  "You feel drained of agility.",
142  "You feel drained of health.",
143  "You feel drained of wisdom.",
144  "You feel drained of charisma.",
145  "You feel drained of intelligence.",
146  "You feel drained of power."
147 };
148 
150 const char *const restore_msg[NUM_STATS] = {
151  "You feel your strength return.",
152  "You feel your agility return.",
153  "You feel your health return.",
154  "You feel your wisdom return.",
155  "You feel your charisma return.",
156  "You feel your intelligence return.",
157  "You feel your power return."
158 };
159 
161 const char *const gain_msg[NUM_STATS] = {
162  "You feel stronger.",
163  "You feel more agile.",
164  "You feel healthy.",
165  "You feel wiser.",
166  "You seem to look better.",
167  "You feel smarter.",
168  "You feel more potent."
169 };
170 
172 const char *const lose_msg[NUM_STATS] = {
173  "You feel weaker!",
174  "You feel clumsy!",
175  "You feel less healthy!",
176  "You feel foolish!",
177  "You look ugly!",
178  "You feel stupid!",
179  "You feel less potent!"
180 };
181 
183 const char *const statname[NUM_STATS] = {
184  "strength",
185  "dexterity",
186  "constitution",
187  "wisdom",
188  "charisma",
189  "intelligence",
190  "power"
191 };
192 
194 const char *const short_stat_name[NUM_STATS] = {
195  "Str",
196  "Dex",
197  "Con",
198  "Wis",
199  "Cha",
200  "Int",
201  "Pow"
202 };
203 
218 void set_attr_value(living *stats, int attr, int8_t value) {
219  switch (attr) {
220  case STRENGTH:
221  stats->Str = value;
222  break;
223 
224  case DEXTERITY:
225  stats->Dex = value;
226  break;
227 
228  case CONSTITUTION:
229  stats->Con = value;
230  break;
231 
232  case WISDOM:
233  stats->Wis = value;
234  break;
235 
236  case POWER:
237  stats->Pow = value;
238  break;
239 
240  case CHARISMA:
241  stats->Cha = value;
242  break;
243 
244  case INTELLIGENCE:
245  stats->Int = value;
246  break;
247  }
248 }
249 
264 void change_attr_value(living *stats, int attr, int8_t value) {
265  if (value == 0)
266  return;
267  switch (attr) {
268  case STRENGTH:
269  stats->Str += value;
270  break;
271 
272  case DEXTERITY:
273  stats->Dex += value;
274  break;
275 
276  case CONSTITUTION:
277  stats->Con += value;
278  break;
279 
280  case WISDOM:
281  stats->Wis += value;
282  break;
283 
284  case POWER:
285  stats->Pow += value;
286  break;
287 
288  case CHARISMA:
289  stats->Cha += value;
290  break;
291 
292  case INTELLIGENCE:
293  stats->Int += value;
294  break;
295 
296  default:
297  LOG(llevError, "Invalid attribute in change_attr_value: %d\n", attr);
298  }
299 }
300 
313 int8_t get_attr_value(const living *stats, int attr) {
314  switch (attr) {
315  case STRENGTH:
316  return(stats->Str);
317 
318  case DEXTERITY:
319  return(stats->Dex);
320 
321  case CONSTITUTION:
322  return(stats->Con);
323 
324  case WISDOM:
325  return(stats->Wis);
326 
327  case CHARISMA:
328  return(stats->Cha);
329 
330  case INTELLIGENCE:
331  return(stats->Int);
332 
333  case POWER:
334  return(stats->Pow);
335  }
336  return 0;
337 }
338 
354 void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat) {
355  int i, v;
356  for (i = 0; i < NUM_STATS; i++)
357  if ((v = get_attr_value(stats, i)) > max_stat)
358  set_attr_value(stats, i, max_stat);
359  else if (v < min_stat)
360  set_attr_value(stats, i, min_stat);
361 }
362 
363 
369 #define DIFF_MSG(flag, subtype1, subtype2, msg1, msg2) \
370  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, (flag > 0) ? subtype1 : subtype2, (flag > 0) ? msg1 : msg2);
371 
394 int change_abil(object *op, object *tmp) {
395  int flag = QUERY_FLAG(tmp, FLAG_APPLIED) ? 1 : -1, i, j, success = 0;
396  object refop;
397  int potion_max = 0;
398 
399  /* remember what object was like before it was changed. note that
400  * refop is a local copy of op only to be used for detecting changes
401  * found by fix_object. refop is not a real object
402  */
403  memcpy(&refop, op, sizeof(object));
404 
405  if (op->type == PLAYER) {
406  if (tmp->type == POTION) {
407  potion_max = 1;
408  for (j = 0; j < NUM_STATS; j++) {
409  int nstat, ostat;
410 
411  ostat = get_attr_value(&(op->contr->orig_stats), j);
412  i = get_attr_value(&(tmp->stats), j);
413 
414  /* nstat is what the stat will be after use of the potion */
415  nstat = flag*i+ostat;
416 
417  /* Do some bounds checking. While I don't think any
418  * potions do so right now, there is the potential for potions
419  * that adjust that stat by more than one point, so we need
420  * to allow for that.
421  */
422  if (nstat < 1 && i*flag < 0)
423  nstat = 1;
424  else if (nstat > 20+get_attr_value(&(op->arch->clone.stats), j)) {
425  nstat = 20+get_attr_value(&(op->arch->clone.stats), j);
426  }
427  if (nstat != ostat) {
428  set_attr_value(&(op->contr->orig_stats), j, nstat);
429  potion_max = 0;
430  } else if (i) {
431  /* potion is useless - player has already hit the natural maximum */
432  potion_max = 1;
433  }
434  }
435  /* This section of code ups the characters normal stats also. I am not
436  * sure if this is strictly necessary, being that fix_object probably
437  * recalculates this anyway.
438  */
439  for (j = 0; j < NUM_STATS; j++)
440  change_attr_value(&(op->stats), j, flag*get_attr_value(&(tmp->stats), j));
442  } /* end of potion handling code */
443  }
444 
445  /* reset attributes that fix_object doesn't reset since it doesn't search
446  * everything to set
447  */
448  if (flag == -1) {
449  op->attacktype &= ~tmp->attacktype;
450  op->path_attuned &= ~tmp->path_attuned;
451  op->path_repelled &= ~tmp->path_repelled;
452  op->path_denied &= ~tmp->path_denied;
453  /* Presuming here that creatures only have move_type,
454  * and not the other move_ fields.
455  */
456  op->move_type &= ~tmp->move_type;
457  }
458 
459  /* call fix_object since op object could have whatever attribute due
460  * to multiple items. if fix_object always has to be called after
461  * change_ability then might as well call it from here
462  */
463  fix_object(op);
464 
465  /* Fix player won't add the bows ability to the player, so don't
466  * print out message if this is a bow.
467  */
468  if (tmp->attacktype&AT_CONFUSION && tmp->type != BOW) {
469  success = 1;
471  "Your hands begin to glow red.",
472  "Your hands stop glowing red.");
473  }
474  if (QUERY_FLAG(op, FLAG_LIFESAVE) != QUERY_FLAG(&refop, FLAG_LIFESAVE)) {
475  success = 1;
477  "You feel very protected.",
478  "You don't feel protected anymore.");
479  }
481  success = 1;
483  "A magic force shimmers around you.",
484  "The magic force fades away.");
485  }
487  success = 1;
489  "You feel more safe now, somehow.",
490  "Suddenly you feel less safe, somehow.");
491  }
492  /* movement type has changed. We don't care about cases where
493  * user has multiple items giving the same type appled like we
494  * used to - that is more work than what we gain, plus messages
495  * can be misleading (a little higher could be miscontrued from
496  * from fly high)
497  */
498  if (tmp->move_type && op->move_type != refop.move_type) {
499  success = 1;
500 
501  /* MOVE_FLY_HIGH trumps MOVE_FLY_LOW - changing your move_fly_low
502  * status doesn't make a difference if you are flying high
503  */
504  if (tmp->move_type&MOVE_FLY_LOW && !(op->move_type&MOVE_FLY_HIGH)) {
506  "You start to float in the air!",
507  "You float down to the ground.");
508  }
509 
510  if (tmp->move_type&MOVE_FLY_HIGH) {
511  /* double conditional - second case covers if you have move_fly_low -
512  * in that case, you don't actually land
513  */
515  "You soar into the air!.",
516  (op->move_type&MOVE_FLY_LOW ? "You glide closer to the ground.":
517  "You float down to the ground."));
518  }
519  if (tmp->move_type&MOVE_SWIM)
521  "You feel ready for a swim",
522  "You no longer feel like swimming");
523 
524  /* Changing move status may mean you are affected by things you weren't before */
526  }
527 
528  /* becoming UNDEAD... a special treatment for this flag. Only those not
529  * originally undead may change their status
530  */
531  if (!QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
532  if (QUERY_FLAG(op, FLAG_UNDEAD) != QUERY_FLAG(&refop, FLAG_UNDEAD)) {
533  success = 1;
534  if (flag > 0) {
535  if (op->race)
536  free_string(op->race);
537  op->race = add_string("undead");
538  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_RACE, "Your lifeforce drains away!");
539  } else {
540  if (op->race)
541  free_string(op->race);
542  if (op->arch->clone.race)
543  op->race = add_string(op->arch->clone.race);
544  else
545  op->race = NULL;
546  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_RACE, "Your lifeforce returns!");
547  }
548  }
549 
550  if (QUERY_FLAG(op, FLAG_STEALTH) != QUERY_FLAG(&refop, FLAG_STEALTH)) {
551  success = 1;
553  "You walk more quietly.",
554  "You walk more noisily.");
555  }
557  success = 1;
559  "You become transparent.",
560  "You can see yourself.");
561  }
562  /* blinded you can tell if more blinded since blinded player has minimal
563  * vision
564  */
565  if (QUERY_FLAG(tmp, FLAG_BLIND)) {
566  success = 1;
567  if (flag > 0) {
568  if (QUERY_FLAG(op, FLAG_WIZ))
570  else {
573  if (op->type == PLAYER)
574  op->contr->do_los = 1;
575  }
576  } else {
577  if (QUERY_FLAG(op, FLAG_WIZ))
578  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END, "Your mortal self can now see again.");
579  else {
582  if (op->type == PLAYER)
583  op->contr->do_los = 1;
584  }
585  }
586  }
587 
589  success = 1;
590  if (op->type == PLAYER)
591  op->contr->do_los = 1;
593  "Your vision is better in the dark.",
594  "You see less well in the dark.");
595  }
596 
597  if (QUERY_FLAG(op, FLAG_XRAYS) != QUERY_FLAG(&refop, FLAG_XRAYS)) {
598  success = 1;
599  if (flag > 0) {
600  if (QUERY_FLAG(op, FLAG_WIZ))
601  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START, "Your vision becomes a little clearer.");
602  else {
603  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START, "Everything becomes transparent.");
604  if (op->type == PLAYER)
605  op->contr->do_los = 1;
606  }
607  } else {
608  if (QUERY_FLAG(op, FLAG_WIZ))
609  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END, "Your vision becomes a bit out of focus.");
610  else {
611  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END, "Everything suddenly looks very solid.");
612  if (op->type == PLAYER)
613  op->contr->do_los = 1;
614  }
615  }
616  }
617 
618  if (tmp->stats.luck) {
619  success = 1;
621  "You feel more lucky.",
622  "You feel less lucky.");
623  }
624 
625  if (tmp->stats.hp && op->type == PLAYER) {
626  success = 1;
628  "You feel much more healthy!",
629  "You feel much less healthy!");
630  }
631 
632  if (tmp->stats.sp && op->type == PLAYER && tmp->type != SKILL) {
633  success = 1;
635  "You feel one with the powers of magic!",
636  "You suddenly feel very mundane.");
637  }
638 
639  /* for the future when artifacts set this -b.t. */
640  if (tmp->stats.grace && op->type == PLAYER) {
641  success = 1;
643  "You feel closer to your god!",
644  "You suddenly feel less holy.");
645  }
646 
647  if (tmp->stats.wc && op->type == PLAYER) {
648  success = 1;
650  "You feel more confident in combat.",
651  "You feel less confident in combat.");
652  }
653 
654  if (tmp->stats.ac && op->type == PLAYER) {
655  success = 1;
657  "You feel more confident in your dodging skills.",
658  "You feel less confident in your dodging skills.");
659  }
660 
661  if (tmp->stats.exp && tmp->type != SKILL && op->type == PLAYER) {
662  success = 1;
664  "You feel like you're moving faster.",
665  "You feel like you're moving more slowly.");
666  }
667 
668  if (tmp->stats.food && op->type == PLAYER) {
669  success = 1;
671  "You feel your digestion slowing down.",
672  "You feel your digestion speeding up.");
673  }
674 
675  /* Messages for changed resistance */
676  for (i = 0; i < NROFATTACKS; i++) {
677  if (i == ATNR_PHYSICAL)
678  continue; /* Don't display about armour */
679 
680  if (op->resist[i] != refop.resist[i]) {
681  success = 1;
682  if (op->resist[i] > refop.resist[i])
684  "Your resistance to %s rises to %d%%.",
685  change_resist_msg[i], op->resist[i]);
686  else
688  "Your resistance to %s drops to %d%%.",
689  change_resist_msg[i], op->resist[i]);
690  }
691  }
692 
693  if (!potion_max) {
694  for (j = 0; j < NUM_STATS; j++) {
695  if ((i = get_attr_value(&(tmp->stats), j)) != 0) {
696  /* Check that the attribute value isn't already min or max value. */
697  int curr_val = get_attr_value(&op->stats, j);
698  if ((curr_val > MIN_STAT && i < 0) || (curr_val < settings.max_stat && i > 0)) {
699  success = 1;
701  }
702  }
703  }
704  }
705  return success;
706 }
707 
716 void drain_stat(object *op) {
718 }
719 
728 void drain_specific_stat(object *op, int deplete_stats) {
729  object *tmp;
730  archetype *at;
731 
733  if (!at) {
734  return;
735  } else {
736  tmp = arch_present_in_ob(at, op);
737  if (!tmp) {
738  tmp = arch_to_object(at);
741  }
742  }
743 
745  change_attr_value(&tmp->stats, deplete_stats, -1);
746  fix_object(op);
747 }
748 
755 int remove_depletion(object *op, int level) {
756  object *depl;
757  archetype *at;
758  int i, count = 0;
759 
760  if ((at = find_archetype(ARCH_DEPLETION)) == NULL) {
761  return 0;
762  }
763 
764  depl = arch_present_in_ob(at, op);
765 
766  if (depl == NULL)
767  return 0;
768 
769  if (level != -1 && level < op->level)
770  return 0;
771 
772  for (i = 0; i < NUM_STATS; i++) {
773  if (get_attr_value(&depl->stats, i)) {
774  count++;
777  }
778  }
779 
780  object_remove(depl);
782  fix_object(op);
783 
784  return (count == 0) ? 0 : 1;
785 }
786 
796 void change_luck(object *op, int value) {
797  object *tmp;
798  archetype *at;
799  int new_luck;
800 
801  at = find_archetype("luck");
802  if (!at)
803  ;
804  else {
805  tmp = arch_present_in_ob(at, op);
806  if (!tmp) {
807  if (!value)
808  return;
809  tmp = arch_to_object(at);
812  }
813  if (value) {
814  /* Limit the luck value of the bad luck object to +/-100. This
815  * (arbitrary) value prevents overflows (both in the bad luck object and
816  * in op itself).
817  */
818  new_luck = tmp->stats.luck+value;
819  if (new_luck >= -100 && new_luck <= 100) {
820  op->stats.luck += value;
821  tmp->stats.luck = new_luck;
822  }
823  } else {
824  if (!tmp->stats.luck) {
825  return;
826  }
827  /* Randomly change the players luck. Basically, we move it
828  * back neutral (if greater>0, subtract, otherwise add)
829  */
830  if (RANDOM()%(FABS(tmp->stats.luck)) >= RANDOM()%30) {
831  int diff = tmp->stats.luck > 0 ? -1 : 1;
832  op->stats.luck += diff;
833  tmp->stats.luck += diff;
834  }
835  }
836  }
837 }
838 
845 void remove_statbonus(object *op) {
846  op->stats.Str -= op->arch->clone.stats.Str;
847  op->stats.Dex -= op->arch->clone.stats.Dex;
848  op->stats.Con -= op->arch->clone.stats.Con;
849  op->stats.Wis -= op->arch->clone.stats.Wis;
850  op->stats.Pow -= op->arch->clone.stats.Pow;
851  op->stats.Cha -= op->arch->clone.stats.Cha;
852  op->stats.Int -= op->arch->clone.stats.Int;
853  op->contr->orig_stats.Str -= op->arch->clone.stats.Str;
854  op->contr->orig_stats.Dex -= op->arch->clone.stats.Dex;
855  op->contr->orig_stats.Con -= op->arch->clone.stats.Con;
856  op->contr->orig_stats.Wis -= op->arch->clone.stats.Wis;
857  op->contr->orig_stats.Pow -= op->arch->clone.stats.Pow;
858  op->contr->orig_stats.Cha -= op->arch->clone.stats.Cha;
859  op->contr->orig_stats.Int -= op->arch->clone.stats.Int;
860 }
861 
868 void add_statbonus(object *op) {
869  op->stats.Str += op->arch->clone.stats.Str;
870  op->stats.Dex += op->arch->clone.stats.Dex;
871  op->stats.Con += op->arch->clone.stats.Con;
872  op->stats.Wis += op->arch->clone.stats.Wis;
873  op->stats.Pow += op->arch->clone.stats.Pow;
874  op->stats.Cha += op->arch->clone.stats.Cha;
875  op->stats.Int += op->arch->clone.stats.Int;
876  op->contr->orig_stats.Str += op->arch->clone.stats.Str;
877  op->contr->orig_stats.Dex += op->arch->clone.stats.Dex;
878  op->contr->orig_stats.Con += op->arch->clone.stats.Con;
879  op->contr->orig_stats.Wis += op->arch->clone.stats.Wis;
880  op->contr->orig_stats.Pow += op->arch->clone.stats.Pow;
881  op->contr->orig_stats.Cha += op->arch->clone.stats.Cha;
882  op->contr->orig_stats.Int += op->arch->clone.stats.Int;
883 }
884 
897 static void fix_player(object *op, int *ac, int *wc, const object *grace_obj, const object *mana_obj, const object *wc_obj, int weapon_speed, float added_speed)
898 {
899  int pl_level, i;
900  float maxhp, tmpf;
901 
902  if (op->type != PLAYER)
903  return;
904 
906  pl_level = op->level;
907 
908  if (pl_level < 1)
909  pl_level = 1; /* safety, we should always get 1 levels worth of hp! */
910 
911  /*
912  * We store maxhp as a float to hold any fractional hp bonuses,
913  * (eg, 2.5 con bonus). While it may seem simpler to just
914  * do a get_con_bonus() * min(level,10), there is also a 1 hp/level
915  * minimum (including bonus), se we have to do the logic on a
916  * level basis.
917  */
918  maxhp = 0.0;
919  for (i = 1, op->stats.maxhp = 0; i <= pl_level && i <= 10; i++) {
920 
921  tmpf = op->contr->levhp[i]+get_con_bonus(op->stats.Con);
922 
923  /* always get at least 1 hp/level */
924  if (tmpf < 1.0) tmpf = 1.0;
925 
926  maxhp += tmpf;
927  }
928 
929  /* Add 0.5 so that this rounds normally - the cast just drops the
930  * fraction, so 1.5 becomes 1.
931  */
932  op->stats.maxhp = (int)(maxhp + 0.5);
933  if (op->level > 10)
934  op->stats.maxhp += 2 * (op->level - 10);
935 
936  op->stats.maxhp += op->arch->clone.stats.maxhp;
937 
938  if (op->stats.hp > op->stats.maxhp)
939  op->stats.hp = op->stats.maxhp;
940 
941  /* Sp gain is controlled by the level of the player's
942  * relevant experience object (mana_obj, see above) */
943 
944  /* set maxsp */
945  if (!mana_obj || !mana_obj->level) {
946  op->stats.maxsp = 1;
947  } else {
948  float sp_tmp = 0.0, mana_bonus;
949  int mana_lvl_max;
950 
951  mana_lvl_max = (mana_obj->level >10 ? 10: mana_obj->level);
952  mana_bonus = (2.0*get_sp_bonus(op->stats.Pow)+get_sp_bonus(op->stats.Int)) / 3.0;
953 
954  for (i = 1; i <= mana_lvl_max; i++) {
955  float stmp;
956 
957  stmp = op->contr->levsp[i] + mana_bonus;
958 
959  /* Got some extra bonus at first level */
960  if (i == 1) stmp += mana_bonus;
961 
962  if (stmp < 1.0)
963  stmp = 1.0;
964 
965  sp_tmp += stmp;
966  }
967 
968  op->stats.maxsp = (int)sp_tmp+op->arch->clone.stats.maxsp;
969 
970  if (mana_obj->level > 10)
971  op->stats.maxsp += 2 * (mana_obj->level - 10);
972  }
973 
974  /* Characters can get their sp supercharged via rune of transferrance */
975  if (op->stats.sp > op->stats.maxsp*2)
976  op->stats.sp = op->stats.maxsp*2;
977 
978  /* set maxgrace, notice 3-4 lines below it depends on both Wis and Pow */
979  if (!grace_obj || !grace_obj->level) {
980  op->stats.maxgrace = 1;
981  } else {
982  /* store grace in a float - this way, the divisions below don't create
983  * big jumps when you go from level to level - with int's, it then
984  * becomes big jumps when the sums of the bonuses jump to the next
985  * step of 8 - with floats, even fractional ones are useful.
986  */
987  float sp_tmp = 0.0, grace_bonus;
988 
989  grace_bonus = (get_grace_bonus(op->stats.Pow)+2.0*get_grace_bonus(op->stats.Wis)) / 3.0;
990 
991  for (i = 1; i <= grace_obj->level && i <= 10; i++) {
992  float grace_tmp = op->contr->levgrace[i] + grace_bonus;
993 
994  /* Got some extra bonus at first level */
995  if (i == 1)
996  grace_tmp += grace_bonus;
997 
998  if (grace_tmp < 1.0)
999  grace_tmp = 1.0;
1000  sp_tmp += grace_tmp;
1001  }
1002  op->stats.maxgrace = (int)sp_tmp+op->arch->clone.stats.maxgrace;
1003 
1004  /* two grace points per level after 11 */
1005  if (grace_obj->level > 10)
1006  op->stats.maxgrace += 2 * (grace_obj->level - 10);
1007  }
1008  /* No limit on grace vs maxgrace */
1009 
1010  if (op->contr->braced) {
1011  (*ac) += 2;
1012  (*wc) += 4;
1013  } else
1014  (*ac) -= get_dex_bonus(op->stats.Dex);
1015 
1016  /* In new exp/skills system, wc bonuses are related to
1017  * the players level in a relevant exp object (wc_obj)
1018  * not the general player level -b.t.
1019  * I changed this slightly so that wc bonuses are better
1020  * than before. This is to balance out the fact that
1021  * the player no longer gets a personal weapon w/ 1
1022  * improvement every level, now its fighterlevel/5. So
1023  * we give the player a bonus here in wc and dam
1024  * to make up for the change. Note that I left the
1025  * monster bonus the same as before. -b.t.
1026  */
1027 
1028  if (wc_obj && wc_obj->level >= 1) {
1029  const char *wc_in = object_get_value(wc_obj, "wc_increase_rate");
1030  int wc_increase_rate;
1031 
1032  wc_increase_rate = wc_in?atoi(wc_in):5;
1033  assert(wc_increase_rate != 0);
1034 
1035  (*wc) -= get_thaco_bonus(op->stats.Str);
1036  (*wc) -= (wc_obj->level-1)/wc_increase_rate;
1037  op->stats.dam += (wc_obj->level-1)/4;
1038  } else {
1039  (*wc) -= (((op->level-1)/5)+get_thaco_bonus(op->stats.Str));
1040  }
1041  op->stats.dam += get_dam_bonus(op->stats.Str);
1042 
1043  if (op->stats.dam < 1)
1044  op->stats.dam = 1;
1045 
1046  op->speed = MAX_PLAYER_SPEED+get_speed_bonus(op->stats.Dex);
1047 
1048  if (settings.search_items && op->contr->search_str[0])
1049  op->speed -= 0.25;
1050 
1051  if (op->attacktype == 0)
1052  op->attacktype = op->arch->clone.attacktype;
1053 
1054 
1055  /* First block is for encumbrance of the player */
1056 
1057  /* The check for FREE_PLAYER_LOAD_PERCENT < 1.0 is really a safety. One would
1058  * think that it should never be the case if that is set to 1.0, that carrying
1059  * would be above the limit. But it could be if character is weakened and
1060  * was otherwise at limit. Without that safety, could get divide by zeros.
1061  */
1062  if (op->carrying > (get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT)
1063  && (FREE_PLAYER_LOAD_PERCENT < 1.0)) {
1064  int extra_weight = op->carrying-get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT;
1065 
1066  op->contr->character_load = (float)extra_weight/(float)(get_weight_limit(op->stats.Str)*(1.0-FREE_PLAYER_LOAD_PERCENT));
1067 
1068  /* character_load is used for weapon speed below, so sanitize value */
1069  if (op->contr->character_load >= 1.0)
1070  op->contr->character_load = 1.0;
1071 
1072  /* If a character is fully loaded, they will always get cut down to min
1073  * speed no matter what their dex. Note that magic is below, so
1074  * still helps out.
1075  */
1076  if (op->speed > MAX_PLAYER_SPEED)
1077  op->speed -= op->contr->character_load*(op->speed-MIN_PLAYER_SPEED);
1078  else
1079  op->speed -= op->contr->character_load*(MAX_PLAYER_SPEED-MIN_PLAYER_SPEED);
1080  } else {
1081  op->contr->character_load = 0;
1082  }
1083 
1084  /* This block is for weapon speed */
1085  op->weapon_speed = BASE_WEAPON_SPEED+get_speed_bonus(op->stats.Dex)-weapon_speed/20.0+added_speed/10.0;
1086  if (wc_obj) {
1087  op->weapon_speed += 0.005*wc_obj->level;
1088  } else
1089  op->weapon_speed += 0.005*op->level;
1090 
1091  /* character_load=1.0 means character is fully loaded, 0.0 is unloaded. Multiplying
1092  * by 0.2 for penalty is purely arbitrary, but slows things down without completely
1093  * stopping them.
1094  */
1095  op->weapon_speed -= op->contr->character_load*0.2;
1096 
1097  if (op->weapon_speed < 0.05)
1098  op->weapon_speed = 0.05;
1099 
1100  /* It is quite possible that a player's spell costing might have changed,
1101  * so we will check that now.
1102  */
1103  esrv_update_spells(op->contr);
1104 }
1125 void fix_object(object *op) {
1126  int i;
1127  float max = 9, added_speed = 0, speed_reduce_from_disease = 1;
1128  int weapon_speed = 0;
1129  int best_wc = 0, best_ac = 0, wc = 0, ac = 0;
1130  int prot[NROFATTACKS], vuln[NROFATTACKS], potion_resist[NROFATTACKS];
1131  const object *grace_obj = NULL, *mana_obj = NULL, *wc_obj = NULL;
1132 
1133  /* First task is to clear all the values back to their original values */
1134  if (op->type == PLAYER) {
1135  for (i = 0; i < NUM_STATS; i++) {
1136  set_attr_value(&(op->stats), i, get_attr_value(&(op->contr->orig_stats), i));
1137  set_attr_value(&(op->contr->applied_stats), i, 0);
1138  }
1140  op->contr->encumbrance = 0;
1141 
1142  op->attacktype = 0;
1143  op->contr->digestion = 0;
1144  op->contr->gen_hp = 0;
1145  op->contr->gen_sp = 0;
1146  op->contr->gen_grace = 0;
1147  op->contr->gen_sp_armour = 10;
1148  op->contr->item_power = 0;
1149 
1150  /* Don't clobber all the range_ values. range_golem otherwise
1151  * gets reset for no good reason, and we don't want to reset
1152  * range_magic (what spell is readied). These three below
1153  * well get filled in based on what the player has equipped.
1154  */
1155  op->contr->ranges[range_bow] = NULL;
1156  op->contr->ranges[range_misc] = NULL;
1157  op->contr->ranges[range_skill] = NULL;
1158  } /* If player */
1159  memcpy(op->body_used, op->body_info, sizeof(op->body_info));
1160 
1161  if (op->slaying != NULL) {
1162  free_string(op->slaying);
1163  op->slaying = NULL;
1164  }
1165  if (!QUERY_FLAG(op, FLAG_WIZ)) {
1168  }
1169 
1174  if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_SPELL))
1176  if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_MISSILE))
1178  if (!QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
1180  if (!QUERY_FLAG(&op->arch->clone, FLAG_SEE_IN_DARK))
1183 
1184  op->path_attuned = op->arch->clone.path_attuned;
1185  op->path_repelled = op->arch->clone.path_repelled;
1186  op->path_denied = op->arch->clone.path_denied;
1187  op->glow_radius = op->arch->clone.glow_radius;
1188  op->move_type = op->arch->clone.move_type;
1189  op->chosen_skill = NULL;
1190 
1191  /* initializing resistances from the values in player/monster's
1192  * archetype clone
1193  */
1194  memcpy(&op->resist, &op->arch->clone.resist, sizeof(op->resist));
1195 
1196  for (i = 0; i < NROFATTACKS; i++) {
1197  if (op->resist[i] > 0)
1198  prot[i] = op->resist[i], vuln[i] = 0;
1199  else
1200  vuln[i] = -(op->resist[i]), prot[i] = 0;
1201  potion_resist[i] = 0;
1202  }
1203 
1204  wc = op->arch->clone.stats.wc;
1205  op->stats.dam = op->arch->clone.stats.dam;
1206 
1207  /* for players which cannot use armour, they gain AC -1 per 3 levels,
1208  * plus a small amount of physical resist, those poor suckers. ;)
1209  * the fact that maxlevel is factored in could be considered sort of bogus -
1210  * we should probably give them some bonus and cap it off - otherwise,
1211  * basically, if a server updates its max level, these playes may find
1212  * that their protection from physical goes down
1213  */
1214  if (!QUERY_FLAG(op, FLAG_USE_ARMOUR) && op->type == PLAYER) {
1215  ac = MAX(-10, op->arch->clone.stats.ac-op->level/3);
1216  prot[ATNR_PHYSICAL] += ((100-prot[AT_PHYSICAL])*(80*op->level/settings.max_level))/100;
1217  } else
1218  ac = op->arch->clone.stats.ac;
1219 
1220  op->stats.luck = op->arch->clone.stats.luck;
1221  op->speed = op->arch->clone.speed;
1222 
1223  /* OK - we've reset most all the objects attributes to sane values.
1224  * now go through and make adjustments for what the player has equipped.
1225  */
1226 
1227  FOR_INV_PREPARE(op, tmp) {
1228  /* See note in map.c:update_position about making this additive
1229  * since light sources are never applied, need to put check here.
1230  */
1231  if (tmp->glow_radius > op->glow_radius)
1232  op->glow_radius = tmp->glow_radius;
1233 
1234  /* This happens because apply_potion calls change_abil with the potion
1235  * applied so we can tell the player what chagned. But change_abil
1236  * then calls this function.
1237  */
1238  if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == POTION)
1239  continue;
1240 
1241  /* For some things, we don't care what is equipped */
1242  if (tmp->type == SKILL) {
1243  /* Want to take the highest skill here. */
1244  if (IS_MANA_SKILL(tmp->subtype)) {
1245  if (!mana_obj)
1246  mana_obj = tmp;
1247  else if (tmp->level > mana_obj->level)
1248  mana_obj = tmp;
1249  }
1250  if (IS_GRACE_SKILL(tmp->subtype)) {
1251  if (!grace_obj)
1252  grace_obj = tmp;
1253  else if (tmp->level > grace_obj->level)
1254  grace_obj = tmp;
1255  }
1256  }
1257 
1258  /* Container objects are not meant to adjust a players, but other applied
1259  * objects need to make adjustments.
1260  * This block should handle all player specific changes
1261  * The check for Praying is a bit of a hack - god given bonuses are put
1262  * in the praying skill, and the player should always get those.
1263  * It also means we need to put in additional checks for applied below,
1264  * because the skill shouldn't count against body positions being used
1265  * up, etc.
1266  */
1267  if ((QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type != CONTAINER && tmp->type != CLOSE_CON)
1268  || (tmp->type == SKILL && tmp->subtype == SK_PRAYING)) {
1269  if (op->type == PLAYER) {
1270  if (tmp->type == BOW)
1271  op->contr->ranges[range_bow] = tmp;
1272 
1273  if (tmp->type == WAND || tmp->type == ROD)
1274  op->contr->ranges[range_misc] = tmp;
1275 
1276  for (i = 0; i < NUM_STATS; i++) {
1277  int8_t value;
1278 
1279  value = get_attr_value(&(tmp->stats), i);
1280  change_attr_value(&(op->stats), i, value);
1281  if (strcmp(tmp->arch->clone.name, ARCH_DEPLETION) != 0)
1282  change_attr_value(&(op->contr->applied_stats), i, value);
1283  }
1284 
1285  /* For this temporary calculation, allow wider range of stat - if we have
1286  * having that gives +5 and different object that gives -5 and stat
1287  * is maxed, we don't want different results based on order of
1288  * inventory.
1289  */
1291 
1292  /* these are the items that currently can change digestion, regeneration,
1293  * spell point recovery and mana point recovery. Seems sort of an arbitary
1294  * list, but other items store other info into stats array.
1295  */
1296  switch (tmp->type)
1297  {
1298  case WEAPON:
1299  case ARMOUR:
1300  case HELMET:
1301  case SHIELD:
1302  case RING:
1303  case BOOTS:
1304  case GLOVES:
1305  case AMULET:
1306  case GIRDLE:
1307  case BRACERS:
1308  case CLOAK:
1309  case DISEASE:
1310  case FORCE:
1311  case SKILL:
1312  op->contr->digestion += tmp->stats.food;
1313  op->contr->gen_hp += tmp->stats.hp;
1314  op->contr->gen_sp += tmp->stats.sp;
1315  op->contr->gen_grace += tmp->stats.grace;
1316  op->contr->gen_sp_armour += tmp->gen_sp_armour;
1317  /*FALLTHROUGH*/
1318 
1319  /* Bow and skill utils need to update item_power specifically.
1320  * This should fix bug #648
1321  * Daniel Hawkins 2017-08-09
1322  */
1323  case BOW:
1324  case SKILL_TOOL:
1325  op->contr->item_power += tmp->item_power;
1326  break;
1327  }
1328  } /* if this is a player */
1329 
1330  /* Update slots used for items */
1331  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1332  for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1333  op->body_used[i] += tmp->body_info[i];
1334  }
1335 
1336  if (tmp->type == SYMPTOM && tmp->last_sp) {
1337  /* Should take the worst disease of the bunch */
1338  if (((float)tmp->last_sp/100.0) < speed_reduce_from_disease)
1339  speed_reduce_from_disease = (float)tmp->last_sp/100.0;
1340  }
1341 
1342  /* Pos. and neg. protections are counted seperate (-> pro/vuln).
1343  * (Negative protections are calculated extactly like positive.)
1344  * Resistance from potions are treated special as well. If there's
1345  * more than one potion-effect, the bigger prot.-value is taken.
1346  */
1347  if (tmp->type != POTION) {
1348  for (i = 0; i < NROFATTACKS; i++) {
1349  /* Potential for cursed potions, in which case we just can use
1350  * a straight MAX, as potion_resist is initialized to zero.
1351  */
1352  if (tmp->type == POTION_RESIST_EFFECT) {
1353  if (potion_resist[i])
1354  potion_resist[i] = MAX(potion_resist[i], tmp->resist[i]);
1355  else
1356  potion_resist[i] = tmp->resist[i];
1357  } else if (tmp->resist[i] > 0)
1358  prot[i] += ((100-prot[i])*tmp->resist[i])/100;
1359  else if (tmp->resist[i] < 0)
1360  vuln[i] += ((100-vuln[i])*(-tmp->resist[i]))/100;
1361  }
1362  }
1363 
1364  /* There may be other things that should not adjust the attacktype */
1365  if (tmp->type != BOW && tmp->type != SYMPTOM)
1366  op->attacktype |= tmp->attacktype;
1367 
1368  op->path_attuned |= tmp->path_attuned;
1369  op->path_repelled |= tmp->path_repelled;
1370  op->path_denied |= tmp->path_denied;
1371  op->stats.luck += tmp->stats.luck;
1372  op->move_type |= tmp->move_type;
1373 
1380  if (QUERY_FLAG(tmp, FLAG_STEALTH))
1382  if (QUERY_FLAG(tmp, FLAG_XRAYS))
1384  if (QUERY_FLAG(tmp, FLAG_BLIND))
1388  if (QUERY_FLAG(tmp, FLAG_PROBE))
1390 
1391  // Items can make the wielder confused.
1394 
1395  if (QUERY_FLAG(tmp, FLAG_UNDEAD) && !QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
1397 
1398  if (QUERY_FLAG(tmp, FLAG_MAKE_INVIS)) {
1400  op->invisible = 1;
1401  }
1402 
1403  if (tmp->stats.exp && tmp->type != SKILL) {
1404  added_speed += (float)tmp->stats.exp/3.0;
1405  }
1406 
1407  switch (tmp->type) {
1408  /* skills modifying the character -b.t. */
1409  /* for all skills and skill granting objects */
1410  case SKILL:
1411  if (!QUERY_FLAG(tmp, FLAG_APPLIED))
1412  break;
1413 
1414  if (IS_COMBAT_SKILL(tmp->subtype))
1415  wc_obj = tmp;
1416 
1417  if (op->chosen_skill) {
1418  LOG(llevDebug, "fix_object, op %s has multiple skills applied\n", op->name);
1419  }
1420  op->chosen_skill = tmp;
1421  if (tmp->stats.dam > 0) { /* skill is a 'weapon' */
1423  weapon_speed = (int)WEAPON_SPEED(tmp);
1424  if (weapon_speed < 0)
1425  weapon_speed = 0;
1426  op->stats.dam += tmp->stats.dam*(1+(op->chosen_skill->level/9));
1427  op->stats.dam += tmp->magic;
1428  }
1429  if (tmp->stats.wc)
1430  wc -= (tmp->stats.wc+tmp->magic);
1431 
1432  if (tmp->slaying != NULL) {
1433  if (op->slaying != NULL)
1434  free_string(op->slaying);
1435  add_refcount(op->slaying = tmp->slaying);
1436  }
1437 
1438  if (tmp->stats.ac)
1439  ac -= (tmp->stats.ac+tmp->magic);
1440  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1441  op->contr->encumbrance += (int)3*tmp->weight/1000;
1442  if (op->type == PLAYER)
1443  op->contr->ranges[range_skill] = op;
1444  break;
1445 
1446  case SKILL_TOOL:
1447  if (op->chosen_skill) {
1448  LOG(llevDebug, "fix_object, op %s has multiple skills applied\n", op->name);
1449  }
1450  op->chosen_skill = tmp;
1451  if (op->type == PLAYER)
1452  op->contr->ranges[range_skill] = op;
1453  break;
1454 
1455  case SHIELD:
1456  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1457  op->contr->encumbrance += (int)tmp->weight/2000;
1458  /* fall through */
1459  case RING:
1460  case AMULET:
1461  case GIRDLE:
1462  case HELMET:
1463  case BOOTS:
1464  case GLOVES:
1465  case CLOAK:
1466  if (tmp->stats.wc)
1467  wc -= tmp->stats.wc;
1468  if (tmp->stats.dam)
1469  op->stats.dam += (tmp->stats.dam+tmp->magic);
1470  if (tmp->stats.ac)
1471  ac -= (tmp->stats.ac+tmp->magic);
1472  break;
1473 
1474  case WEAPON:
1475  wc -= tmp->stats.wc;
1476  if (tmp->stats.ac && tmp->stats.ac+tmp->magic > 0)
1477  ac -= tmp->stats.ac+tmp->magic;
1478  op->stats.dam += (tmp->stats.dam+tmp->magic);
1479  weapon_speed = ((int)WEAPON_SPEED(tmp)*2-tmp->magic)/2;
1480  if (weapon_speed < 0)
1481  weapon_speed = 0;
1482  if (tmp->slaying != NULL) {
1483  if (op->slaying != NULL)
1484  free_string(op->slaying);
1485  add_refcount(op->slaying = tmp->slaying);
1486  }
1487  /* If there is desire that two handed weapons should do
1488  * extra strength damage, this is where the code should
1489  * go.
1490  */
1491  op->current_weapon = tmp;
1492  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1493  op->contr->encumbrance += (int)3*tmp->weight/1000;
1494  break;
1495 
1496  case ARMOUR: /* Only the best of these three are used: */
1497  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1498  op->contr->encumbrance += (int)tmp->weight/1000;
1499 
1500  /* ARMOUR falls through to here */
1501  /* fall through */
1502  case BRACERS:
1503  case FORCE:
1504  // Code simplification to reduce branching -- we don't need to sub/add ac and wc all the time.
1505  // Daniel Hawkins 2018-05-28
1506  if (tmp->stats.wc) {
1507  // Since we are alreay here, make sure wc stacking also occurs for serpentman players.
1508  if (tmp->type == BRACERS && op->type == PLAYER && op->arch->name && strcmp(op->arch->name, "serpentman_player") == 0)
1509  {
1510  // Apply ac from bracers directly.
1511  // This also grants the side effect that armor and bracer ac are separate for serpentmen,
1512  // But that should be better than the extra bracers being mostly useless.
1513  wc -= tmp->stats.wc;
1514  }
1515  else if (best_wc < tmp->stats.wc) {
1516  wc += best_wc;
1517  best_wc = tmp->stats.wc;
1518  wc -= tmp->stats.wc;
1519  }
1520  }
1521  if (tmp->stats.ac) {
1522  /*
1523  * If we have a serpentman player, then we do bracers differently
1524  * to allow for both bracers they equip to apply to ac, instead of only the best.
1525  *
1526  * Daniel Hawkins 2018-05-28
1527  */
1528  if (tmp->type == BRACERS && op->type == PLAYER && op->arch->name && strcmp(op->arch->name, "serpentman_player") == 0)
1529  {
1530  // Apply ac from bracers directly.
1531  // This also grants the side effect that armor and bracer ac are separate for serpentmen,
1532  // But that should be better than the extra bracers being mostly useless.
1533  ac -= tmp->stats.ac+tmp->magic;
1534  }
1535  else if (best_ac < tmp->stats.ac+tmp->magic) {
1536  ac += best_ac; /* Remove last bonus */
1537  best_ac = tmp->stats.ac+tmp->magic;
1538  ac -= (tmp->stats.ac+tmp->magic);
1539  }
1540  }
1541  if (tmp->stats.dam && tmp->type == BRACERS)
1542  op->stats.dam += (tmp->stats.dam+tmp->magic);
1543  if (ARMOUR_SPEED(tmp) && ARMOUR_SPEED(tmp)/10.0 < max)
1544  max = ARMOUR_SPEED(tmp)/10.0;
1545  break;
1546  } /* switch tmp->type */
1547  } /* item is equipped */
1548  } FOR_INV_FINISH(); /* for loop of items */
1549 
1550  /* We've gone through all the objects the player has equipped. For many things, we
1551  * have generated intermediate values which we now need to assign.
1552  */
1553 
1554  /* 'total resistance = total protections - total vulnerabilities'.
1555  * If there is an uncursed potion in effect, granting more protection
1556  * than that, we take: 'total resistance = resistance from potion'.
1557  * If there is a cursed (and no uncursed) potion in effect, we take
1558  * 'total resistance = vulnerability from cursed potion'.
1559  */
1560  for (i = 0; i < NROFATTACKS; i++) {
1561  op->resist[i] = prot[i]-vuln[i];
1562  if (potion_resist[i]
1563  && ((potion_resist[i] > op->resist[i]) || (potion_resist[i] < 0)))
1564  op->resist[i] = potion_resist[i];
1565  }
1566 
1567  fix_player(op, &ac, &wc, grace_obj, mana_obj, wc_obj, weapon_speed, added_speed);
1568 
1569  op->speed = op->speed*speed_reduce_from_disease;
1570 
1571  /* Max is determined by armour */
1572  if (op->speed > max)
1573  op->speed = max;
1574 
1575  op->speed += added_speed/10.0;
1576 
1577 
1578  /* Put a lower limit on speed. Note with this speed, you move once every
1579  * 20 ticks or so. This amounts to once every 3 seconds of realtime.
1580  */
1581  if (op->speed < 0.05 && op->type == PLAYER)
1582  op->speed = 0.05;
1583  /*
1584  * A lower limit should also apply to monsters. By ensuring speeds are
1585  * loaded in as positive, we can properly do this. Otherwise, slow effects
1586  * either push the monster's speed to be more negative (if we leave the input
1587  * speed as negative) or can reduce the speed by more than the monster's speed,
1588  * making it turn negative (if we load speeds as positive always).
1589  *
1590  * For whatever reason, op->type is 0 for some monsters, making FLAG_MONSTER
1591  * the useful information that indicates whether it is a monster or not.
1592  *
1593  * MIN_ACTIVE_SPEED is super low, so make our speed threshold be about .005 instead
1594  */
1595  if (op->speed < MIN_ACTIVE_SPEED*500 && QUERY_FLAG(op, FLAG_MONSTER)) {
1596  // If added_speed is less than zero, we're probably working with a slow effect.
1597  if (added_speed >= 0)
1598  LOG(llevInfo, "fix_object: Monster %s has negative speed of %f.\n",
1599  op->name ? op->name : "(null)", op->speed);
1600  op->speed = MIN_ACTIVE_SPEED*500;
1601  }
1602 
1603  /* I want to limit the power of small monsters with big weapons: */
1604  if (op->type != PLAYER
1605  && op->stats.dam > op->arch->clone.stats.dam*3)
1606  op->stats.dam = op->arch->clone.stats.dam*3;
1607 
1608  /* Prevent overflows of wc - best you can get is ABS(120) - this
1609  * should be more than enough - remember, AC is also in 8 bits,
1610  * so its value is the same.
1611  */
1612  if (wc > 120)
1613  wc = 120;
1614  else if (wc < -120)
1615  wc = -120;
1616  op->stats.wc = wc;
1617 
1618  if (ac > 120)
1619  ac = 120;
1620  else if (ac < -120)
1621  ac = -120;
1622  op->stats.ac = ac;
1623 
1624  /* if for some reason the creature doesn't have any move type,
1625  * give them walking as a default.
1626  * The second case is a special case - to more closely mimic the
1627  * old behaviour - if your flying, your not walking - just
1628  * one or the other.
1629  */
1630  if (op->move_type == 0)
1631  op->move_type = MOVE_WALK;
1632  else if (op->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
1633  op->move_type &= ~MOVE_WALK;
1634 
1636 }
1637 
1650 int allowed_class(const object *op) {
1651  return op->stats.Dex > 0
1652  && op->stats.Str > 0
1653  && op->stats.Con > 0
1654  && op->stats.Int > 0
1655  && op->stats.Wis > 0
1656  && op->stats.Pow > 0
1657  && op->stats.Cha > 0;
1658 }
1659 
1677 void set_dragon_name(object *pl, const object *abil, const object *skin) {
1678  int atnr = -1; /* attacknumber of highest level */
1679  int level = 0; /* highest level */
1680  int i;
1681 
1682  /* Perhaps do something more clever? */
1683  if (!abil || !skin)
1684  return;
1685 
1686  /* first, look for the highest level */
1687  for (i = 0; i < NROFATTACKS; i++) {
1688  if (atnr_is_dragon_enabled(i)
1689  && (atnr == -1 || abil->resist[i] > abil->resist[atnr])) {
1690  level = abil->resist[i];
1691  atnr = i;
1692  }
1693  }
1694 
1695  /* now if there are equals at highest level, pick the one with focus,
1696  or else at random */
1697  if (atnr_is_dragon_enabled(abil->stats.exp)
1698  && abil->resist[abil->stats.exp] >= level)
1699  atnr = abil->stats.exp;
1700 
1701  level = (int)(level/5.);
1702 
1703  /* now set the new title */
1704  if (pl->contr != NULL) {
1705  player_set_dragon_title(pl->contr, level, attacks[atnr], skin->resist[atnr]);
1706  }
1707 }
1708 
1717 static void dragon_level_gain(object *who) {
1718  object *abil = NULL; /* pointer to dragon ability force*/
1719  object *skin = NULL; /* pointer to dragon skin force*/
1720 
1721  /* now grab the 'dragon_ability'-forces from the player's inventory */
1722  abil = object_find_by_type_and_arch_name(who, FORCE, "dragon_ability_force");
1723  skin = object_find_by_type_and_arch_name(who, FORCE, "dragon_skin_force");
1724  /* if the force is missing -> bail out */
1725  if (abil == NULL)
1726  return;
1727 
1728  /* The ability_force keeps track of maximum level ever achieved.
1729  * New abilties can only be gained by surpassing this max level
1730  */
1731  if (who->level > abil->level) {
1732  /* increase our focused ability */
1733  int lev = ++(abil->resist[abil->stats.exp]);
1734 
1735  if (lev > 0) {
1736  /* try to hand out a new ability-gift
1737  * if not the right level, this will handout nothing.
1738  */
1739  dragon_ability_gain(who, (int)abil->stats.exp, lev);
1740  }
1741 
1742  if (abil->last_eat > 0 && atnr_is_dragon_enabled(abil->last_eat)) {
1743  /* apply new ability focus */
1745  "Your metabolism now focuses on %s!",
1746  change_resist_msg[abil->last_eat]);
1747 
1748  abil->stats.exp = abil->last_eat;
1749  abil->last_eat = 0;
1750  }
1751 
1752  abil->level = who->level;
1753  }
1754 
1755  /* last but not least, set the new title for the dragon */
1756  set_dragon_name(who, abil, skin);
1757 }
1758 
1777 object *give_skill_by_name(object *op, const char *skill_name) {
1778  object *skill_obj;
1779  archetype *skill_arch;
1780 
1781  skill_arch = get_archetype_by_skill_name(skill_name, SKILL);
1782  if (!skill_arch) {
1783  LOG(llevError, "add_player_exp: couldn't find skill %s\n", skill_name);
1784  return NULL;
1785  }
1786  skill_obj = arch_to_object(skill_arch); /* never returns NULL. */
1787 
1788  /* clear the flag - exp goes into this bucket, but player
1789  * still doesn't know it.
1790  */
1791  CLEAR_FLAG(skill_obj, FLAG_CAN_USE_SKILL);
1792  skill_obj->stats.exp = 0;
1793  skill_obj->level = 1;
1794  object_insert_in_ob(skill_obj, op);
1795  if (op->contr) {
1797  }
1798  return skill_obj;
1799 }
1800 
1817 void player_lvl_adj(object *who, object *op) {
1818  char buf[MAX_BUF];
1819 
1820  assert(who);
1821 
1822  if (!op) /* when rolling stats */
1823  op = who;
1824 
1825  if (op->level < settings.max_level && op->stats.exp >= level_exp(op->level+1, who->expmul)) {
1826  do{
1827  op->level++;
1828 
1829  if (op == who && op->stats.exp > 1 && is_dragon_pl(who))
1831 
1832  /* Only roll these if it is the player (who) that gained the level */
1833  if (op == who && (who->level < 11) && who->type == PLAYER) {
1834  who->contr->levhp[who->level] = die_roll(2, 4, who, PREFER_HIGH)+1;
1835  who->contr->levsp[who->level] = die_roll(2, 3, who, PREFER_HIGH);
1836  who->contr->levgrace[who->level] = die_roll(2, 2, who, PREFER_HIGH)-1;
1837  }
1838 
1839  fix_object(who); // TODO: Call this only once per function call?
1840  if (op->level > 1) {
1841  if (op->type != PLAYER)
1842  snprintf(buf, sizeof(buf), "You are now level %d in the %s skill.", op->level, op->name);
1843  else
1844  snprintf(buf, sizeof(buf), "You are now level %d.", op->level);
1845 
1847  }
1848  } while (op->level < settings.max_level && op->stats.exp >= level_exp(op->level+1, who->expmul)); /* To increase more levels */
1849  } else if (op->level > 1 && op->stats.exp < level_exp(op->level, who->expmul)) {
1850  do{
1851  op->level--;
1852  fix_object(who); // TODO: Call this only once per function call?
1853  if (op->type != PLAYER)
1854  snprintf(buf, sizeof(buf), "You are now level %d in the %s skill.", op->level, op->name);
1855  else
1856  snprintf(buf, sizeof(buf), "You are now level %d.", op->level);
1857 
1859  } while (op->level > 1 && op->stats.exp < level_exp(op->level, who->expmul)); /* To decrease more levels */
1860  }
1861 }
1862 
1872 int64_t level_exp(int level, double expmul) {
1873  if (level > settings.max_level)
1874  return expmul*levels[settings.max_level];
1875  return expmul*levels[level];
1876 }
1877 
1884 int exp_level(int64_t exp) {
1885  int level = 1;
1886  while ( level < settings.max_level && levels[level+1] <= exp )
1887  ++level;
1888  return level;
1889 }
1890 
1901 void calc_perm_exp(object *op) {
1902  if (op->total_exp < op->stats.exp)
1903  op->total_exp = op->stats.exp;
1904 
1905  /* Cap permanent experience. */
1906  if (op->total_exp < 0)
1907  op->total_exp = 0;
1908  else if (op->total_exp > MAX_EXPERIENCE * 100 / settings.permanent_exp_ratio)
1909  op->total_exp = MAX_EXPERIENCE * 100 / settings.permanent_exp_ratio;
1910 }
1911 
1919 object* find_applied_skill_by_name(const object* op, const char* name) {
1920  for (int i = 0; i < MAX_SKILLS; i++) {
1921  if (op->contr->last_skill_ob[i] != NULL) {
1922  // Skill objects can be removed without updating last_skill_ob. Clean
1923  // them up here if that's the case.
1924  if (QUERY_FLAG(op->contr->last_skill_ob[i], FLAG_REMOVED)) {
1925  LOG(llevDebug, "pruning removed object from last_skill_ob\n");
1926  op->contr->last_skill_ob[i] = NULL;
1927  continue;
1928  }
1929 
1930  if (op->contr->last_skill_ob[i]->skill != NULL) {
1931  if (!strcmp(op->contr->last_skill_ob[i]->skill, name)) {
1932  return op->contr->last_skill_ob[i];
1933  }
1934  } else {
1935  LOG(llevError,
1936  "%s's skill object %s does not have a skill name\n",
1937  op->name, op->contr->last_skill_ob[i]->name);
1938  }
1939  }
1940  }
1941  return NULL;
1942 }
1943 
1958 static void add_player_exp(object *op, int64_t exp, const char *skill_name, int flag) {
1959  object *skill_obj = NULL;
1960  int64_t limit, exp_to_add;
1961  int64_t added_skill_exp = 0, added_skill_total_exp = 0;
1962 
1963  /* prevents some forms of abuse. */
1964  if (op->contr->braced)
1965  exp = exp/5;
1966 
1967  /* Try to find the matching skill.
1968  * We do a shortcut/time saving mechanism first - see if it matches
1969  * chosen_skill. This means we don't need to search through
1970  * the players inventory.
1971  */
1972  if (skill_name) {
1973  if (op->chosen_skill
1974  && op->chosen_skill->type == SKILL
1975  && !strcmp(skill_name, op->chosen_skill->skill))
1976  skill_obj = op->chosen_skill;
1977  else {
1978  skill_obj = find_applied_skill_by_name(op, skill_name);
1979 
1980  /* Player doesn't have the skill. Check to see what to do, and give
1981  * it to the player if necessary
1982  */
1983  if (!skill_obj) {
1984  if (flag == SK_EXP_NONE)
1985  return;
1986  else if (flag == SK_EXP_ADD_SKILL)
1987  skill_obj = give_skill_by_name(op, skill_name);
1988  }
1989  }
1990  }
1991 
1992  /* Basically, you can never gain more experience in one shot
1993  * than half what you need to gain for next level.
1994  */
1995  exp_to_add = exp;
1996  /*
1997  * Make sure we aren't trying to go backwards when we hit maximum level,
1998  * but make sure we can still add to our permanent experience.
1999  *
2000  * -- Daniel Hawkins 2015-05-24
2001  */
2002  if (op->level == settings.max_level)
2003  limit = levels[op->level] / 2;
2004  else
2005  limit = (levels[op->level+1]-levels[op->level])/2;
2006 
2007  if (exp_to_add > limit)
2008  exp_to_add = limit;
2009 
2010  if (skill_obj) {
2011  exp_to_add = exp;
2012  /*
2013  * Make sure we aren't trying to go backwards when we hit maximum level,
2014  * but make sure we can still add to our permanent experience.
2015  *
2016  * -- Daniel Hawkins 2015-05-24
2017  */
2018  if (skill_obj->level == settings.max_level)
2019  limit = levels[skill_obj->level] / 2;
2020  else
2021  limit = (levels[skill_obj->level+1]-levels[skill_obj->level])/2;
2022 
2023  if (exp_to_add > limit)
2024  exp_to_add = limit;
2025  added_skill_exp = skill_obj->stats.exp;
2026  ADD_EXP(skill_obj->stats.exp, exp_to_add);
2027  added_skill_exp = skill_obj->stats.exp - added_skill_exp;
2029  added_skill_total_exp = skill_obj->total_exp;
2030  ADD_TOTALEXP(skill_obj->total_exp, exp_to_add);
2031  added_skill_total_exp = skill_obj->total_exp - added_skill_total_exp;
2032  calc_perm_exp(skill_obj);
2033  }
2034  player_lvl_adj(op, skill_obj);
2035  }
2036  else {
2037  added_skill_exp = added_skill_total_exp = exp_to_add;
2038  }
2039 
2040  ADD_EXP(op->stats.exp, (float)added_skill_exp*(skill_obj ? skill_obj->expmul : 1));
2042  ADD_TOTALEXP(op->total_exp, (float)added_skill_total_exp*(skill_obj ? skill_obj->expmul : 1));
2043  calc_perm_exp(op);
2044  }
2045 
2046  player_lvl_adj(op, NULL);
2047 }
2048 
2064 int64_t check_exp_loss(const object *op, int64_t exp) {
2065  int64_t del_exp;
2066 
2067  if (exp > op->stats.exp)
2068  exp = op->stats.exp;
2070  del_exp = (op->stats.exp-PERM_EXP(op->total_exp))*PERM_EXP_MAX_LOSS_RATIO;
2071  if (del_exp < 0)
2072  del_exp = 0;
2073  if (exp > del_exp)
2074  exp = del_exp;
2075  }
2076  return exp;
2077 }
2078 
2089 int64_t check_exp_adjust(const object *op, int64_t exp) {
2090  if (exp < 0)
2091  return check_exp_loss(op, exp);
2092  else
2093  return MIN(exp, MAX_EXPERIENCE-op->stats.exp);
2094 }
2095 
2118 static void subtract_player_exp(object *op, int64_t exp, const char *skill, int flag) {
2119  float fraction = (float)exp/(float)op->stats.exp;
2120  int64_t del_exp;
2121 
2123  if (tmp->type == SKILL && tmp->stats.exp) {
2124  if (flag == SK_SUBTRACT_SKILL_EXP && skill && !strcmp(tmp->skill, skill)) {
2125  del_exp = check_exp_loss(tmp, exp);
2126  tmp->stats.exp -= del_exp;
2127  player_lvl_adj(op, tmp);
2128  } else if (flag != SK_SUBTRACT_SKILL_EXP) {
2129  /* only want to process other skills if we are not trying
2130  * to match a specific skill.
2131  */
2132  del_exp = check_exp_loss(tmp, tmp->stats.exp*fraction);
2133  tmp->stats.exp -= del_exp;
2134  player_lvl_adj(op, tmp);
2135  }
2136  }
2137  FOR_INV_FINISH();
2138  if (flag != SK_SUBTRACT_SKILL_EXP) {
2139  del_exp = check_exp_loss(op, exp);
2140  op->stats.exp -= del_exp;
2141  player_lvl_adj(op, NULL);
2142  }
2143 }
2144 
2166 void change_exp(object *op, int64_t exp, const char *skill_name, int flag) {
2167  /* safety */
2168  if (!op) {
2169  LOG(llevError, "change_exp() called for null object!\n");
2170  return;
2171  }
2172 
2173  /* if no change in exp, just return - most of the below code
2174  * won't do anything if the value is 0 anyways.
2175  */
2176  if (exp == 0)
2177  return;
2178 
2179  /* Monsters are easy - we just adjust their exp - we
2180  * don't adjust level, since in most cases it is unrelated to
2181  * the exp they have - the monsters exp represents what its
2182  * worth.
2183  */
2184  if (op->type != PLAYER && op->type != WEAPON) {
2185  /* Sanity check */
2186  if (!QUERY_FLAG(op, FLAG_ALIVE))
2187  return;
2188 
2189  /* reset exp to max allowed value. We subtract from
2190  * MAX_EXPERIENCE to prevent overflows. If the player somehow has
2191  * more than max exp, just return.
2192  */
2193  if (exp > 0 && (op->stats.exp > (MAX_EXPERIENCE-exp))) {
2194  exp = MAX_EXPERIENCE-op->stats.exp;
2195  if (exp < 0)
2196  return;
2197  }
2198 
2199  op->stats.exp += exp;
2200  } else if (op->type == WEAPON) { /* Weapons -- this allows us to make magic weapons that get stronger the more they are used. */
2201  // Handle adding exp -- Don't use level because other stuff already uses that.
2202  // The caller should determine what percentage of base exp this is.
2203  ADD_TOTALEXP(op->total_exp, exp);
2204  if (exp > 0) {
2205  // Check for a level-up
2206  while (level_exp(op->item_power+1, 1) < op->total_exp) {
2207  ++(op->item_power);
2208  }
2209  } else { /* Removing exp allows for the weapon's power to be reset if needed. */
2210  // Recalculate level
2211  while (level_exp(op->item_power, 1) > op->total_exp) {
2212  --(op->item_power);
2213  }
2214  }
2215  } else { /* Players only */
2216  if (exp > 0)
2217  add_player_exp(op, exp, skill_name, flag);
2218  else
2219  subtract_player_exp(op, FABS(exp), skill_name, flag);
2220  }
2221 }
2222 
2232  int64_t loss;
2233  int64_t percentage_loss; /* defined by the setting 'death_penalty_percent' */
2234  int64_t level_loss; /* defined by the setting 'death_penalty_levels */
2235 
2237  if (tmp->type == SKILL && tmp->stats.exp) {
2238  percentage_loss = tmp->stats.exp*settings.death_penalty_ratio/100;
2239  level_loss = tmp->stats.exp-levels[MAX(0, tmp->level-settings.death_penalty_level)];
2240 
2241  /* With the revised exp system, you can get cases where
2242  * losing several levels would still require that you have more
2243  * exp than you currently have - this is true if the levels
2244  * tables is a lot harder.
2245  */
2246  if (level_loss < 0)
2247  level_loss = 0;
2248 
2249  loss = check_exp_loss(tmp, MIN(level_loss, percentage_loss));
2250 
2251  tmp->stats.exp -= loss;
2252  player_lvl_adj(op, tmp);
2253  }
2254  FOR_INV_FINISH();
2255 
2256  percentage_loss = op->stats.exp*settings.death_penalty_ratio/100;
2257  level_loss = op->stats.exp-levels[MAX(0, op->level-settings.death_penalty_level)];
2258  if (level_loss < 0)
2259  level_loss = 0;
2260  loss = check_exp_loss(op, MIN(level_loss, percentage_loss));
2261 
2262  op->stats.exp -= loss;
2263  player_lvl_adj(op, NULL);
2264 }
2265 
2280 int did_make_save(const object *op, int level, int bonus) {
2281  if (level > MAX_SAVE_LEVEL)
2283 
2284  if ((random_roll(1, 20, op, PREFER_HIGH)+bonus) < savethrow[level])
2285  return 0;
2286  return 1;
2287 }
2288 
2310 void share_exp(object *op, int64_t exp, const char *skill, int flag) {
2311  int shares = 0, count = 0;
2312  player *pl;
2313  partylist *party;
2314 
2315  if (op->type != PLAYER || op->contr->party == NULL) {
2316  change_exp(op, exp, skill, 0);
2317  return;
2318  }
2319 
2320  party = op->contr->party;
2321 
2322  for (pl = first_player; pl != NULL; pl = pl->next) {
2323  if (party && pl->ob->contr->party == party && on_same_map(pl->ob, op)) {
2324  count++;
2325  shares += (pl->ob->level+4);
2326  }
2327  }
2328 
2329  assert(shares > 0);
2330 
2331  if (count == 1 || shares > exp)
2332  change_exp(op, exp, skill, flag);
2333  else {
2334  int64_t share = exp/shares, given = 0, nexp;
2335  for (pl = first_player; pl != NULL; pl = pl->next) {
2336  if (party && pl->ob->contr->party == party && on_same_map(pl->ob, op)) {
2337  nexp = (pl->ob->level+4)*share;
2338  change_exp(pl->ob, nexp, skill, SK_EXP_TOTAL);
2339  given += nexp;
2340  }
2341  }
2342  exp -= given;
2343  /* give any remainder to the player */
2344  change_exp(op, exp, skill, flag);
2345  }
2346 }
2347 
2348 int get_cha_bonus(int stat) {
2350 }
2351 
2352 int get_dex_bonus(int stat) {
2354 }
2355 
2356 int get_thaco_bonus(int stat) {
2358 }
2359 
2360 uint32_t get_weight_limit(int stat) {
2362 }
2363 
2364 int get_learn_spell(int stat) {
2366 }
2367 
2368 int get_cleric_chance(int stat) {
2370 }
2371 
2372 int get_turn_bonus(int stat) {
2374 }
2375 
2376 int get_dam_bonus(int stat) {
2378 }
2379 
2380 float get_speed_bonus(int stat) {
2382 }
2383 
2384 int get_fear_bonus(int stat) {
2386 }
2387 
2388 static float get_con_bonus(int stat) {
2390 }
2391 
2392 static float get_sp_bonus(int stat) {
2394 }
2395 
2396 static float get_grace_bonus(int stat) {
2398 }
2399 
2408 static size_t get_index(int stat, size_t max_index) {
2409  size_t index;
2410 
2411  if (stat < 0) {
2412  return 0;
2413  }
2414 
2415  index = (size_t)stat;
2416  return MIN(index, max_index);
2417 }
2418 
2436 static int load_table_int(int **bonuses, FILE *fp, char *bonus_name)
2437 {
2438  char buf[MAX_BUF], *cp;
2439  int on_stat = 0, tmp_bonus;
2440 
2441  *bonuses = static_cast<int *>(calloc(settings.max_stat+1, sizeof(int)));
2442 
2443  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2444  if (buf[0] == '#')
2445  continue;
2446 
2447  /* Skip over empty lines */
2448  if (buf[0] == '\n')
2449  continue;
2450 
2451  /* Do not care about opening brace */
2452  if (buf[0] == '{')
2453  continue;
2454 
2455  if (buf[0] == '}') {
2456  if ((on_stat-1) != settings.max_stat) {
2457  LOG(llevError,"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2458  on_stat, settings.max_stat, bonus_name);
2459  return 1;
2460  }
2461  else return 0;
2462  }
2463 
2464  /* If not any of the above values, must be the stat table,
2465  * or so we hope.
2466  */
2467  cp = buf;
2468  while (*cp != 0) {
2469  /* Skip over any non numbers */
2470  while (!isdigit(*cp) && *cp!='.' && *cp!='-' && *cp!='+' && *cp != 0)
2471  cp++;
2472 
2473  if (*cp == 0) break;
2474 
2475  tmp_bonus = atoi(cp);
2476 
2477  if (on_stat > settings.max_stat) {
2478  LOG(llevError,"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2479  buf, bonus_name);
2480  return 1;
2481  }
2482  (*bonuses)[on_stat] = tmp_bonus;
2483  on_stat++;
2484 
2485  /* Skip over any digits, as that is the number we just processed */
2486  while ((isdigit(*cp) || *cp=='-' || *cp=='+') && *cp != 0)
2487  cp++;
2488  }
2489  }
2490  /* This should never happen - we should always get the closing brace */
2491  LOG(llevError,"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2492  return 1;
2493 }
2494 
2512 static int load_table_float(float **bonuses, FILE *fp, char *bonus_name)
2513 {
2514  char buf[MAX_BUF], *cp;
2515  int on_stat = 0;
2516  float tmp_bonus;
2517 
2518  *bonuses = static_cast<float *>(calloc(settings.max_stat+1, sizeof(float)));
2519 
2520  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2521  if (buf[0] == '#')
2522  continue;
2523 
2524  /* Skip over empty lines */
2525  if (buf[0] == '\n')
2526  continue;
2527 
2528  /* Do not care about opening brace */
2529  if (buf[0] == '{')
2530  continue;
2531 
2532  if (buf[0] == '}') {
2533  if ((on_stat-1) != settings.max_stat) {
2534  LOG(llevError,"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2535  on_stat, settings.max_stat, bonus_name);
2536  return 1;
2537  }
2538  else return 0;
2539  }
2540 
2541  /* If not any of the above values, must be the stat table,
2542  * or so we hope.
2543  */
2544  cp = buf;
2545  while (*cp != 0) {
2546  /* Skip over any non numbers */
2547  while (!isdigit(*cp) && *cp!='.' && *cp!='-' && *cp!='+' && *cp != 0)
2548  cp++;
2549 
2550  if (*cp == 0) break;
2551 
2552  tmp_bonus = atof(cp);
2553 
2554  if (on_stat > settings.max_stat) {
2555  LOG(llevError,"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2556  buf, bonus_name);
2557  return 1;
2558  }
2559  (*bonuses)[on_stat] = tmp_bonus;
2560  on_stat++;
2561 
2562  /* Skip over any digits, as that is the number we just processed
2563  * since this is floats, also skip over any dots.
2564  */
2565  while ((isdigit(*cp) || *cp=='-' || *cp=='+' || *cp=='.') && *cp != 0)
2566  cp++;
2567  }
2568  }
2569  /* This should never happen - we should always get the closing brace */
2570  LOG(llevError,"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2571  return 1;
2572 }
2573 
2574 
2592 void init_stats(int reload) {
2593  char buf[MAX_BUF], *cp;
2594  int error=0, i, oldmax = settings.max_stat;
2595  FILE *fp;
2596  float *new_float_bonuses[NUM_FLOAT_BONUSES];
2597  int *new_int_bonuses[NUM_INT_BONUSES];
2598 
2599  snprintf(buf, sizeof(buf), "%s/stat_bonus", settings.confdir);
2600 
2601  memset(new_int_bonuses, 0, NUM_INT_BONUSES * sizeof(int));
2602  memset(new_float_bonuses, 0, NUM_FLOAT_BONUSES * sizeof(float));
2603 
2604  if ((fp = fopen(buf, "r")) == NULL) {
2605  LOG(llevError, "Fatal error: could not open experience table (%s)\n", buf);
2606  if (reload) return;
2607  else exit(1);
2608  }
2609  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2610  if (buf[0] == '#')
2611  continue;
2612 
2613  /* eliminate newline */
2614  if ((cp = strrchr(buf, '\n')) != NULL)
2615  *cp = '\0';
2616 
2617  /* Skip over empty lines */
2618  if (buf[0] == 0)
2619  continue;
2620 
2621  /* Skip over leading spaces */
2622  cp = buf;
2623  while (isspace(*cp) && *cp != 0)
2624  cp++;
2625 
2626  if (!strncasecmp(cp, "max_stat", 8)) {
2627  int newmax = atoi(cp+8);
2628 
2629  /* newmax must be at least MIN_STAT and we do not currently
2630  * cupport decrease max stat on the fly - why this might be possible,
2631  * bounds checking for all objects would be needed, potentionally resetting
2632  * them.
2633  * If this is a reload, then on error, we just return without doing work.
2634  * If this is initial load, having an invalid stat range is an error, so
2635  * exit the program.
2636  */
2637  if (newmax < MIN_STAT || newmax < settings.max_stat) {
2638  LOG(llevError, "Got invalid max_stat (%d) from stat_bonus file\n", newmax);
2639  fclose(fp);
2640  if (reload) return;
2641  else exit(1);
2642  }
2643  settings.max_stat = newmax;
2644  continue;
2645  }
2646  /* max_stat needs to be set before any of the bonus values - we
2647  * need to know how large to make the array.
2648  */
2649  if (settings.max_stat == 0) {
2650  LOG(llevError, "Got bonus line or otherwise unknown value before max stat! (%s)\n",
2651  buf);
2652  fclose(fp);
2653 
2654  if (reload) {
2655  return;
2656  } else {
2657  exit(1);
2658  }
2659  }
2660 
2661  for (i=0; i<NUM_INT_BONUSES; i++) {
2662  if (!strncasecmp(cp, int_bonus_names[i], strlen(int_bonus_names[i]))) {
2663  error = load_table_int(&new_int_bonuses[i], fp, cp);
2664  break;
2665  }
2666  }
2667  /* If we did not find a match in the int bonuses, check the
2668  * float bonuses now.
2669  */
2670  if (i == NUM_INT_BONUSES) {
2671  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2672  if (!strncasecmp(cp, float_bonus_names[i], strlen(float_bonus_names[i]))) {
2673  error = load_table_float(&new_float_bonuses[i], fp, cp);
2674  break;
2675  }
2676  }
2677  /* This may not actually be a critical error */
2678  if (i == NUM_FLOAT_BONUSES) {
2679  LOG(llevError,"Unknown line in stat_bonus file: %s\n", buf);
2680  }
2681  }
2682  if (error) break;
2683  }
2684  fclose(fp);
2685 
2686  /* Make sure that we have load tables for all the bonuses.
2687  * This is critical on initial load, but on reloads, it enusres that
2688  * all the bonus data matches.
2689  */
2690  for (i=0; i<NUM_INT_BONUSES; i++) {
2691  if (!new_int_bonuses[i]) {
2692  LOG(llevError,"No bonus loaded for %s\n", int_bonus_names[i]);
2693  error=2;
2694  }
2695  }
2696 
2697  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2698  if (!new_float_bonuses[i]) {
2699  LOG(llevError,"No bonus loaded for %s\n", float_bonus_names[i]);
2700  error=2;
2701  }
2702  }
2703 
2704  /* If we got an error, we just free up the data we read in and return/exit.
2705  * if no error, we make the tables we just read in into the default
2706  * tables.
2707  */
2708  if (error) {
2709  if (error==1)
2710  LOG(llevError,"Got error reading stat_bonus: %s\n", buf);
2711 
2712  if (reload) {
2713  for (i=0; i<NUM_INT_BONUSES; i++)
2714  if (new_int_bonuses[i]) FREE_AND_CLEAR(new_int_bonuses[i]);
2715  for (i=0; i<NUM_FLOAT_BONUSES; i++)
2716  if (new_float_bonuses[i]) FREE_AND_CLEAR(new_float_bonuses[i]);
2717  settings.max_stat = oldmax;
2718  } else {
2719  exit(1);
2720  }
2721  } else {
2722  /* Everything check out - now copy the data into
2723  * the live arrays.
2724  */
2725  for (i=0; i<NUM_INT_BONUSES; i++) {
2726  free(int_bonuses[i]);
2727  int_bonuses[i] = new_int_bonuses[i];
2728  new_int_bonuses[i] = NULL;
2729  }
2730 
2731  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2732  free(float_bonuses[i]);
2733  float_bonuses[i] = new_float_bonuses[i];
2734  new_float_bonuses[i] = NULL;
2735  }
2736  }
2737 }
INT_THAC0_BONUS
#define INT_THAC0_BONUS
Definition: living.cpp:65
ADD_TOTALEXP
#define ADD_TOTALEXP(exptotal, exp)
Definition: living.cpp:42
fix_player
static void fix_player(object *op, int *ac, int *wc, const object *grace_obj, const object *mana_obj, const object *wc_obj, int weapon_speed, float added_speed)
Definition: living.cpp:897
get_grace_bonus
static float get_grace_bonus(int stat)
Definition: living.cpp:2396
PLAYER
@ PLAYER
Definition: object.h:110
global.h
get_cha_bonus
int get_cha_bonus(int stat)
Definition: living.cpp:2348
first_player
player * first_player
Definition: init.cpp:106
settings
struct Settings settings
Definition: init.cpp:139
Settings::max_level
int16_t max_level
Definition: global.h:302
DIFF_MSG
#define DIFF_MSG(flag, subtype1, subtype2, msg1, msg2)
Definition: living.cpp:369
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:13
FLAG_CONFUSED
#define FLAG_CONFUSED
Definition: define.h:311
BOW
@ BOW
Definition: object.h:121
BRACERS
@ BRACERS
Definition: object.h:220
levels
int64_t * levels
Definition: exp.cpp:26
find_applied_skill_by_name
object * find_applied_skill_by_name(const object *op, const char *name)
Definition: living.cpp:1919
CLOSE_CON
@ CLOSE_CON
Definition: object.h:232
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
SYMPTOM
@ SYMPTOM
Definition: object.h:248
WAND
@ WAND
Definition: object.h:223
range_bow
@ range_bow
Definition: player.h:31
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
FLAG_UNDEAD
#define FLAG_UNDEAD
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
drain_specific_stat
void drain_specific_stat(object *op, int deplete_stats)
Definition: living.cpp:728
GLOVES
@ GLOVES
Definition: object.h:216
GIRDLE
@ GIRDLE
Definition: object.h:226
get_fear_bonus
int get_fear_bonus(int stat)
Definition: living.cpp:2384
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
FLAG_REFL_MISSILE
#define FLAG_REFL_MISSILE
Definition: define.h:273
ARCH_DEPLETION
#define ARCH_DEPLETION
Definition: object.h:579
MSG_TYPE_ATTRIBUTE_ATTACKTYPE_GAIN
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_GAIN
Definition: newclient.h:549
MSG_TYPE_ATTRIBUTE_LEVEL_GAIN
#define MSG_TYPE_ATTRIBUTE_LEVEL_GAIN
Definition: newclient.h:570
get_cleric_chance
int get_cleric_chance(int stat)
Definition: living.cpp:2368
FLOAT_SP_BONUS
#define FLOAT_SP_BONUS
Definition: living.cpp:87
liv::Str
int8_t Str
Definition: living.h:36
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
Definition: newclient.h:574
Settings::permanent_exp_ratio
uint8_t permanent_exp_ratio
Definition: global.h:258
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
NUM_FLOAT_BONUSES
#define NUM_FLOAT_BONUSES
Definition: living.cpp:89
pl
Definition: player.h:105
float_bonuses
static float * float_bonuses[NUM_FLOAT_BONUSES]
Definition: living.cpp:90
ARMOUR
@ ARMOUR
Definition: object.h:123
int_bonus_names
static const char * int_bonus_names[NUM_INT_BONUSES]
Definition: living.cpp:75
give_skill_by_name
object * give_skill_by_name(object *op, const char *skill_name)
Definition: living.cpp:1777
WEAPON
@ WEAPON
Definition: object.h:122
arch_present_in_ob
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.cpp:3215
SK_PRAYING
@ SK_PRAYING
Definition: skills.h:49
MSG_TYPE_ATTRIBUTE
#define MSG_TYPE_ATTRIBUTE
Definition: newclient.h:405
MSG_TYPE_ATTRIBUTE_PROTECTION_LOSS
#define MSG_TYPE_ATTRIBUTE_PROTECTION_LOSS
Definition: newclient.h:556
check_exp_adjust
int64_t check_exp_adjust(const object *op, int64_t exp)
Definition: living.cpp:2089
get_sp_bonus
static float get_sp_bonus(int stat)
Definition: living.cpp:2392
CHARISMA
@ CHARISMA
Definition: living.h:15
AMULET
@ AMULET
Definition: object.h:142
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
calc_perm_exp
void calc_perm_exp(object *op)
Definition: living.cpp:1901
MIN
#define MIN(x, y)
Definition: compat.h:21
gain_msg
const char *const gain_msg[NUM_STATS]
Definition: living.cpp:161
pl::ob
object * ob
Definition: player.h:176
allowed_class
int allowed_class(const object *op)
Definition: living.cpp:1650
SKILL
@ SKILL
Definition: object.h:146
INT_WEIGHT_LIMIT
#define INT_WEIGHT_LIMIT
Definition: living.cpp:66
esrv_update_spells
void esrv_update_spells(player *pl)
Definition: main.cpp:386
fix_object
void fix_object(object *op)
Definition: living.cpp:1125
Ice.tmp
int tmp
Definition: Ice.py:207
NDI_RED
#define NDI_RED
Definition: newclient.h:245
FLOAT_CON_BONUS
#define FLOAT_CON_BONUS
Definition: living.cpp:85
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
POTION_RESIST_EFFECT
@ POTION_RESIST_EFFECT
Definition: object.h:228
ARMOUR_SPEED
#define ARMOUR_SPEED(xyz)
Definition: define.h:466
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
curse_on_apply.ac
ac
Definition: curse_on_apply.py:4
FLAG_PROBE
#define FLAG_PROBE
Definition: define.h:257
SK_EXP_NONE
#define SK_EXP_NONE
Definition: skills.h:80
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4339
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
NDI_BLUE
#define NDI_BLUE
Definition: newclient.h:247
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
FLAG_BLIND
#define FLAG_BLIND
Definition: define.h:336
buf
StringBuffer * buf
Definition: readable.cpp:1611
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2851
INT_TURN_BONUS
#define INT_TURN_BONUS
Definition: living.cpp:59
MAX
#define MAX(x, y)
Definition: compat.h:24
WISDOM
@ WISDOM
Definition: living.h:14
obj::expmul
double expmul
Definition: object.h:403
MIN_PLAYER_SPEED
#define MIN_PLAYER_SPEED
Definition: config.h:96
lose_msg
const char *const lose_msg[NUM_STATS]
Definition: living.cpp:172
MIN_STAT
#define MIN_STAT
Definition: define.h:33
archt
Definition: object.h:472
dragon_ability_gain
void dragon_ability_gain(object *who, int atnr, int level)
Definition: main.cpp:365
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
add_statbonus
void add_statbonus(object *op)
Definition: living.cpp:868
player_set_dragon_title
void player_set_dragon_title(struct pl *pl, int level, const char *attack, int skin_resist)
Definition: player.cpp:202
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.cpp:194
load_table_int
static int load_table_int(int **bonuses, FILE *fp, char *bonus_name)
Definition: living.cpp:2436
Settings::spell_encumbrance
uint8_t spell_encumbrance
Definition: global.h:268
autojail.who
who
Definition: autojail.py:3
CLOAK
@ CLOAK
Definition: object.h:207
liv::exp
int64_t exp
Definition: living.h:47
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
pl::next
struct pl * next
Definition: player.h:106
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:563
HELMET
@ HELMET
Definition: object.h:139
MSG_TYPE_ATTRIBUTE_STAT_LOSS
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:569
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.cpp:210
MSG_TYPE_ATTRIBUTE_RACE
#define MSG_TYPE_ATTRIBUTE_RACE
Definition: newclient.h:564
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
Definition: newclient.h:565
Settings::death_penalty_ratio
uint8_t death_penalty_ratio
Definition: global.h:259
NUM_INT_BONUSES
#define NUM_INT_BONUSES
Definition: living.cpp:67
MSG_TYPE_ATTRIBUTE_PROTECTION_GAIN
#define MSG_TYPE_ATTRIBUTE_PROTECTION_GAIN
Definition: newclient.h:555
POTION
@ POTION
Definition: object.h:114
subtract_player_exp
static void subtract_player_exp(object *op, int64_t exp, const char *skill, int flag)
Definition: living.cpp:2118
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
obj::total_exp
int64_t total_exp
Definition: object.h:377
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
liv::Cha
int8_t Cha
Definition: living.h:36
FLOAT_DEX_BONUS
#define FLOAT_DEX_BONUS
Definition: living.cpp:86
ROD
@ ROD
Definition: object.h:112
CONTAINER
@ CONTAINER
Definition: object.h:234
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.cpp:218
load_table_float
static int load_table_float(float **bonuses, FILE *fp, char *bonus_name)
Definition: living.cpp:2512
MSG_TYPE_ATTRIBUTE_STAT_GAIN
#define MSG_TYPE_ATTRIBUTE_STAT_GAIN
Definition: newclient.h:568
exp_level
int exp_level(int64_t exp)
Definition: living.cpp:1884
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
Definition: define.h:328
change_resist_msg
const char *const change_resist_msg[NROFATTACKS]
Definition: init.cpp:70
MSG_TYPE_ATTRIBUTE_MOVE
#define MSG_TYPE_ATTRIBUTE_MOVE
Definition: newclient.h:562
POWER
@ POWER
Definition: living.h:17
object_update_speed
void object_update_speed(object *op)
Definition: object.cpp:1349
IS_GRACE_SKILL
#define IS_GRACE_SKILL(num)
Definition: skills.h:120
player_lvl_adj
void player_lvl_adj(object *who, object *op)
Definition: living.cpp:1817
INT_CHA_BONUS
#define INT_CHA_BONUS
Definition: living.cpp:62
get_index
static size_t get_index(int stat, size_t max_index)
Definition: living.cpp:2408
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.cpp:2166
int_bonuses
static int * int_bonuses[NUM_INT_BONUSES]
Definition: living.cpp:69
disinfect.count
int count
Definition: disinfect.py:7
say.max
dictionary max
Definition: say.py:148
dragon_level_gain
static void dragon_level_gain(object *who)
Definition: living.cpp:1717
level_exp
int64_t level_exp(int level, double expmul)
Definition: living.cpp:1872
liv::Con
int8_t Con
Definition: living.h:36
Settings::confdir
const char * confdir
Definition: global.h:247
sproto.h
drain_msg
const char *const drain_msg[NUM_STATS]
Definition: living.cpp:139
statname
const char *const statname[NUM_STATS]
Definition: living.cpp:183
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
Definition: define.h:321
IS_COMBAT_SKILL
#define IS_COMBAT_SKILL(num)
Definition: skills.h:91
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.cpp:42
RING
@ RING
Definition: object.h:188
liv::Int
int8_t Int
Definition: living.h:36
add_player_exp
static void add_player_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.cpp:1958
get_dam_bonus
int get_dam_bonus(int stat)
Definition: living.cpp:2376
DEXTERITY
@ DEXTERITY
Definition: living.h:12
Settings::death_penalty_level
uint8_t death_penalty_level
Definition: global.h:260
liv
Definition: living.h:35
party_struct
Definition: party.h:10
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
apply_death_exp_penalty
void apply_death_exp_penalty(object *op)
Definition: living.cpp:2231
get_dex_bonus
int get_dex_bonus(int stat)
Definition: living.cpp:2352
MAX_BUF
#define MAX_BUF
Definition: define.h:35
MAX_EXPERIENCE
#define MAX_EXPERIENCE
Definition: living.cpp:99
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2360
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
RANDOM
#define RANDOM()
Definition: define.h:644
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
ADD_EXP
#define ADD_EXP(exptotal, exp)
Definition: living.cpp:41
change_abil
int change_abil(object *op, object *tmp)
Definition: living.cpp:394
MSG_TYPE_ATTRIBUTE_ATTACKTYPE_LOSS
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_LOSS
Definition: newclient.h:550
range_misc
@ range_misc
Definition: player.h:33
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
PERM_EXP
#define PERM_EXP(exptotal)
Definition: global.h:230
FLAG_REFL_SPELL
#define FLAG_REFL_SPELL
Definition: define.h:275
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
llevInfo
@ llevInfo
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
obj::stats
living stats
Definition: object.h:376
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Definition: global.h:193
get_thaco_bonus
int get_thaco_bonus(int stat)
Definition: living.cpp:2356
obj::contr
struct pl * contr
Definition: object.h:282
WEAPON_SPEED
#define WEAPON_SPEED(xyz)
Definition: define.h:468
is_dragon_pl
int is_dragon_pl(const object *op)
Definition: player.cpp:122
get_learn_spell
int get_learn_spell(int stat)
Definition: living.cpp:2364
liv::Dex
int8_t Dex
Definition: living.h:36
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
Definition: define.h:295
DISEASE
@ DISEASE
Definition: object.h:247
attacks
const char *const attacks[NROFATTACKS]
Definition: living.cpp:129
change_attr_value
void change_attr_value(living *stats, int attr, int8_t value)
Definition: living.cpp:264
liv::Wis
int8_t Wis
Definition: living.h:36
drain_stat
void drain_stat(object *op)
Definition: living.cpp:716
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
STRENGTH
@ STRENGTH
Definition: living.h:11
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:270
get_turn_bonus
int get_turn_bonus(int stat)
Definition: living.cpp:2372
change_luck
void change_luck(object *op, int value)
Definition: living.cpp:796
get_speed_bonus
float get_speed_bonus(int stat)
Definition: living.cpp:2380
did_make_save
int did_make_save(const object *op, int level, int bonus)
Definition: living.cpp:2280
Settings::max_stat
uint8_t max_stat
Definition: global.h:324
SKILL_TOOL
@ SKILL_TOOL
Definition: object.h:192
init_stats
void init_stats(int reload)
Definition: living.cpp:2592
INT_DAM_BONUS
#define INT_DAM_BONUS
Definition: living.cpp:64
on_same_map
int on_same_map(const object *op1, const object *op2)
Definition: map.cpp:2665
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
npc_dialog.index
int index
Definition: npc_dialog.py:102
SK_SUBTRACT_SKILL_EXP
#define SK_SUBTRACT_SKILL_EXP
Definition: skills.h:81
share_exp
void share_exp(object *op, int64_t exp, const char *skill, int flag)
Definition: living.cpp:2310
atnr_is_dragon_enabled
int atnr_is_dragon_enabled(int attacknr)
Definition: player.cpp:103
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.cpp:122
object_find_by_type_and_arch_name
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Definition: object.cpp:4270
obj::last_eat
int32_t last_eat
Definition: object.h:364
obj::move_type
MoveType move_type
Definition: object.h:432
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:230
level
int level
Definition: readable.cpp:1609
float_bonus_names
static const char * float_bonus_names[NUM_FLOAT_BONUSES]
Definition: living.cpp:91
INT_FEAR_BONUS
#define INT_FEAR_BONUS
Definition: living.cpp:58
restore_msg
const char *const restore_msg[NUM_STATS]
Definition: living.cpp:150
MAX_SAVE_LEVEL
#define MAX_SAVE_LEVEL
Definition: living.cpp:103
PERM_EXP_MAX_LOSS_RATIO
#define PERM_EXP_MAX_LOSS_RATIO
Definition: config.h:282
make_face_from_files.int
int
Definition: make_face_from_files.py:26
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Definition: define.h:639
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
Definition: newclient.h:567
check_exp_loss
int64_t check_exp_loss(const object *op, int64_t exp)
Definition: living.cpp:2064
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.cpp:308
MOVE_FLY_HIGH
#define MOVE_FLY_HIGH
Definition: define.h:394
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
MSG_TYPE_ATTRIBUTE_LEVEL_LOSS
#define MSG_TYPE_ATTRIBUTE_LEVEL_LOSS
Definition: newclient.h:571
remove_depletion
int remove_depletion(object *op, int level)
Definition: living.cpp:755
AT_CONFUSION
#define AT_CONFUSION
Definition: attack.h:81
SK_EXP_TOTAL
#define SK_EXP_TOTAL
Definition: skills.h:79
remove_statbonus
void remove_statbonus(object *op)
Definition: living.cpp:845
object_check_move_on
int object_check_move_on(object *op, object *originator)
Definition: object.cpp:3005
FLOAT_GRACE_BONUS
#define FLOAT_GRACE_BONUS
Definition: living.cpp:88
INT_LEARN_SPELL
#define INT_LEARN_SPELL
Definition: living.cpp:61
SK_EXP_ADD_SKILL
#define SK_EXP_ADD_SKILL
Definition: skills.h:78
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
report.error
def error(pl)
Definition: report.py:43
Settings::search_items
uint8_t search_items
Definition: global.h:267
MOVE_SWIM
#define MOVE_SWIM
Definition: define.h:396
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.cpp:313
range_skill
@ range_skill
Definition: player.h:35
savethrow
static const int savethrow[MAX_SAVE_LEVEL+1]
Definition: living.cpp:113
MAX_PLAYER_SPEED
#define MAX_PLAYER_SPEED
Definition: config.h:97
INTELLIGENCE
@ INTELLIGENCE
Definition: living.h:16
BOOTS
@ BOOTS
Definition: object.h:215
pl::party
partylist * party
Definition: player.h:202
TRUE
#define TRUE
Definition: compat.h:11
link_player_skills
void link_player_skills(object *op)
Definition: player.cpp:287
get_con_bonus
static float get_con_bonus(int stat)
Definition: living.cpp:2388
FLAG_READY_WEAPON
#define FLAG_READY_WEAPON
Definition: define.h:334
set_dragon_name
void set_dragon_name(object *pl, const object *abil, const object *skin)
Definition: living.cpp:1677
SHIELD
@ SHIELD
Definition: object.h:138
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
check_stat_bounds
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Definition: living.cpp:354
living.h
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:349
if
if(!(yy_init))
Definition: loader.c:2626
NUM_STATS
@ NUM_STATS
Definition: living.h:18
INT_CLERIC_CHANCE
#define INT_CLERIC_CHANCE
Definition: living.cpp:60
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
FORCE
@ FORCE
Definition: object.h:227
BASE_WEAPON_SPEED
#define BASE_WEAPON_SPEED
Definition: config.h:108
liv::Pow
int8_t Pow
Definition: living.h:36
INT_DEX_BONUS
#define INT_DEX_BONUS
Definition: living.cpp:63
obj::level
int16_t level
Definition: object.h:359
MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START
Definition: newclient.h:572
CONSTITUTION
@ CONSTITUTION
Definition: living.h:13
llevDebug
@ llevDebug
Definition: logger.h:13
FLAG_LIFESAVE
#define FLAG_LIFESAVE
Definition: define.h:305
IS_MANA_SKILL
#define IS_MANA_SKILL(num)
Definition: skills.h:106
give.name
name
Definition: give.py:27
FREE_PLAYER_LOAD_PERCENT
#define FREE_PLAYER_LOAD_PERCENT
Definition: config.h:98
get_archetype_by_skill_name
archetype * get_archetype_by_skill_name(const char *skill, int type)
Definition: arch.cpp:80
level
Definition: level.py:1