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