Crossfire Server, Trunk  R21524
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  }
487  if (QUERY_FLAG(op, FLAG_REFL_SPELL) != QUERY_FLAG(&refop, FLAG_REFL_SPELL)) {
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 */
526  object_check_move_on(op, op);
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  }
557  if (QUERY_FLAG(op, FLAG_MAKE_INVIS) != QUERY_FLAG(&refop, FLAG_MAKE_INVIS)) {
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))
570  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START, "Your mortal self is blinded.");
571  else {
573  SET_FLAG(op, FLAG_BLIND);
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 {
582  CLEAR_FLAG(op, FLAG_BLIND);
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  success = 1;
699  }
700  }
701  }
702  return success;
703 }
704 
713 void drain_stat(object *op) {
715 }
716 
725 void drain_specific_stat(object *op, int deplete_stats) {
726  object *tmp;
727  archetype *at;
728 
730  if (!at) {
731  return;
732  } else {
733  tmp = arch_present_in_ob(at, op);
734  if (!tmp) {
735  tmp = arch_to_object(at);
736  tmp = object_insert_in_ob(tmp, op);
737  SET_FLAG(tmp, FLAG_APPLIED);
738  }
739  }
740 
742  change_attr_value(&tmp->stats, deplete_stats, -1);
743  fix_object(op);
744 }
745 
752 int remove_depletion(object *op, int level) {
753  object *depl;
754  archetype *at;
755  int i, count = 0;
756 
757  if ((at = find_archetype(ARCH_DEPLETION)) == NULL) {
758  return 0;
759  }
760 
761  depl = arch_present_in_ob(at, op);
762 
763  if (depl == NULL)
764  return 0;
765 
766  if (level != -1 && level < op->level)
767  return 0;
768 
769  for (i = 0; i < NUM_STATS; i++) {
770  if (get_attr_value(&depl->stats, i)) {
771  count++;
774  }
775  }
776 
777  object_remove(depl);
779  fix_object(op);
780 
781  return (count == 0) ? 0 : 1;
782 }
783 
793 void change_luck(object *op, int value) {
794  object *tmp;
795  archetype *at;
796  int new_luck;
797 
798  at = find_archetype("luck");
799  if (!at)
800  ;
801  else {
802  tmp = arch_present_in_ob(at, op);
803  if (!tmp) {
804  if (!value)
805  return;
806  tmp = arch_to_object(at);
807  tmp = object_insert_in_ob(tmp, op);
808  SET_FLAG(tmp, FLAG_APPLIED);
809  }
810  if (value) {
811  /* Limit the luck value of the bad luck object to +/-100. This
812  * (arbitrary) value prevents overflows (both in the bad luck object and
813  * in op itself).
814  */
815  new_luck = tmp->stats.luck+value;
816  if (new_luck >= -100 && new_luck <= 100) {
817  op->stats.luck += value;
818  tmp->stats.luck = new_luck;
819  }
820  } else {
821  if (!tmp->stats.luck) {
822  return;
823  }
824  /* Randomly change the players luck. Basically, we move it
825  * back neutral (if greater>0, subtract, otherwise add)
826  */
827  if (RANDOM()%(FABS(tmp->stats.luck)) >= RANDOM()%30) {
828  int diff = tmp->stats.luck > 0 ? -1 : 1;
829  op->stats.luck += diff;
830  tmp->stats.luck += diff;
831  }
832  }
833  }
834 }
835 
842 void remove_statbonus(object *op) {
843  op->stats.Str -= op->arch->clone.stats.Str;
844  op->stats.Dex -= op->arch->clone.stats.Dex;
845  op->stats.Con -= op->arch->clone.stats.Con;
846  op->stats.Wis -= op->arch->clone.stats.Wis;
847  op->stats.Pow -= op->arch->clone.stats.Pow;
848  op->stats.Cha -= op->arch->clone.stats.Cha;
849  op->stats.Int -= op->arch->clone.stats.Int;
850  op->contr->orig_stats.Str -= op->arch->clone.stats.Str;
851  op->contr->orig_stats.Dex -= op->arch->clone.stats.Dex;
852  op->contr->orig_stats.Con -= op->arch->clone.stats.Con;
853  op->contr->orig_stats.Wis -= op->arch->clone.stats.Wis;
854  op->contr->orig_stats.Pow -= op->arch->clone.stats.Pow;
855  op->contr->orig_stats.Cha -= op->arch->clone.stats.Cha;
856  op->contr->orig_stats.Int -= op->arch->clone.stats.Int;
857 }
858 
865 void add_statbonus(object *op) {
866  op->stats.Str += op->arch->clone.stats.Str;
867  op->stats.Dex += op->arch->clone.stats.Dex;
868  op->stats.Con += op->arch->clone.stats.Con;
869  op->stats.Wis += op->arch->clone.stats.Wis;
870  op->stats.Pow += op->arch->clone.stats.Pow;
871  op->stats.Cha += op->arch->clone.stats.Cha;
872  op->stats.Int += op->arch->clone.stats.Int;
873  op->contr->orig_stats.Str += op->arch->clone.stats.Str;
874  op->contr->orig_stats.Dex += op->arch->clone.stats.Dex;
875  op->contr->orig_stats.Con += op->arch->clone.stats.Con;
876  op->contr->orig_stats.Wis += op->arch->clone.stats.Wis;
877  op->contr->orig_stats.Pow += op->arch->clone.stats.Pow;
878  op->contr->orig_stats.Cha += op->arch->clone.stats.Cha;
879  op->contr->orig_stats.Int += op->arch->clone.stats.Int;
880 }
881 
894 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)
895 {
896  int pl_level, i;
897  float character_load = 0.0, maxhp, tmpf;
898 
899  if (op->type != PLAYER)
900  return;
901 
903  pl_level = op->level;
904 
905  if (pl_level < 1)
906  pl_level = 1; /* safety, we should always get 1 levels worth of hp! */
907 
908  /*
909  * We store maxhp as a float to hold any fractional hp bonuses,
910  * (eg, 2.5 con bonus). While it may seem simpler to just
911  * do a get_con_bonus() * min(level,10), there is also a 1 hp/level
912  * minimum (including bonus), se we have to do the logic on a
913  * level basis.
914  */
915  maxhp = 0.0;
916  for (i = 1, op->stats.maxhp = 0; i <= pl_level && i <= 10; i++) {
917 
918  tmpf = op->contr->levhp[i]+get_con_bonus(op->stats.Con);
919 
920  /* always get at least 1 hp/level */
921  if (tmpf < 1.0) tmpf = 1.0;
922 
923  maxhp += tmpf;
924  }
925 
926  /* Add 0.5 so that this rounds normally - the cast just drops the
927  * fraction, so 1.5 becomes 1.
928  */
929  op->stats.maxhp = (int)(maxhp + 0.5);
930  if (op->level > 10)
931  op->stats.maxhp += 2 * (op->level - 10);
932 
933  op->stats.maxhp += op->arch->clone.stats.maxhp;
934 
935  if (op->stats.hp > op->stats.maxhp)
936  op->stats.hp = op->stats.maxhp;
937 
938  /* Sp gain is controlled by the level of the player's
939  * relevant experience object (mana_obj, see above) */
940 
941  /* set maxsp */
942  if (!mana_obj || !mana_obj->level) {
943  op->stats.maxsp = 1;
944  } else {
945  float sp_tmp = 0.0, mana_bonus;
946  int mana_lvl_max;
947 
948  mana_lvl_max = (mana_obj->level >10 ? 10: mana_obj->level);
949  mana_bonus = (2.0*get_sp_bonus(op->stats.Pow)+get_sp_bonus(op->stats.Int)) / 3.0;
950 
951  for (i = 1; i <= mana_lvl_max; i++) {
952  float stmp;
953 
954  stmp = op->contr->levsp[i] + mana_bonus;
955 
956  /* Got some extra bonus at first level */
957  if (i == 1) stmp += mana_bonus;
958 
959  if (stmp < 1.0)
960  stmp = 1.0;
961 
962  sp_tmp += stmp;
963  }
964 
965  op->stats.maxsp = (int)sp_tmp+op->arch->clone.stats.maxsp;
966 
967  if (mana_obj->level > 10)
968  op->stats.maxsp += 2 * (mana_obj->level - 10);
969  }
970 
971  /* Characters can get their sp supercharged via rune of transferrance */
972  if (op->stats.sp > op->stats.maxsp*2)
973  op->stats.sp = op->stats.maxsp*2;
974 
975  /* set maxgrace, notice 3-4 lines below it depends on both Wis and Pow */
976  if (!grace_obj || !grace_obj->level) {
977  op->stats.maxgrace = 1;
978  } else {
979  /* store grace in a float - this way, the divisions below don't create
980  * big jumps when you go from level to level - with int's, it then
981  * becomes big jumps when the sums of the bonuses jump to the next
982  * step of 8 - with floats, even fractional ones are useful.
983  */
984  float sp_tmp = 0.0, grace_bonus;
985 
986  grace_bonus = (get_grace_bonus(op->stats.Pow)+2.0*get_grace_bonus(op->stats.Wis)) / 3.0;
987 
988  for (i = 1; i <= grace_obj->level && i <= 10; i++) {
989  float grace_tmp = op->contr->levgrace[i] + grace_bonus;
990 
991  /* Got some extra bonus at first level */
992  if (i == 1)
993  grace_tmp += grace_bonus;
994 
995  if (grace_tmp < 1.0)
996  grace_tmp = 1.0;
997  sp_tmp += grace_tmp;
998  }
999  op->stats.maxgrace = (int)sp_tmp+op->arch->clone.stats.maxgrace;
1000 
1001  /* two grace points per level after 11 */
1002  if (grace_obj->level > 10)
1003  op->stats.maxgrace += 2 * (grace_obj->level - 10);
1004  }
1005  /* No limit on grace vs maxgrace */
1006 
1007  if (op->contr->braced) {
1008  (*ac) += 2;
1009  (*wc) += 4;
1010  } else
1011  (*ac) -= get_dex_bonus(op->stats.Dex);
1012 
1013  /* In new exp/skills system, wc bonuses are related to
1014  * the players level in a relevant exp object (wc_obj)
1015  * not the general player level -b.t.
1016  * I changed this slightly so that wc bonuses are better
1017  * than before. This is to balance out the fact that
1018  * the player no longer gets a personal weapon w/ 1
1019  * improvement every level, now its fighterlevel/5. So
1020  * we give the player a bonus here in wc and dam
1021  * to make up for the change. Note that I left the
1022  * monster bonus the same as before. -b.t.
1023  */
1024 
1025  if (wc_obj && wc_obj->level >= 1) {
1026  const char *wc_in = object_get_value(wc_obj, "wc_increase_rate");
1027  int wc_increase_rate;
1028 
1029  wc_increase_rate = wc_in?atoi(wc_in):5;
1030  assert(wc_increase_rate != 0);
1031 
1032  (*wc) -= get_thaco_bonus(op->stats.Str);
1033  (*wc) -= (wc_obj->level-1)/wc_increase_rate;
1034  op->stats.dam += (wc_obj->level-1)/4;
1035  } else {
1036  (*wc) -= (((op->level-1)/5)+get_thaco_bonus(op->stats.Str));
1037  }
1038  op->stats.dam += get_dam_bonus(op->stats.Str);
1039 
1040  if (op->stats.dam < 1)
1041  op->stats.dam = 1;
1042 
1044 
1045  if (settings.search_items && op->contr->search_str[0])
1046  op->speed -= 0.25;
1047 
1048  if (op->attacktype == 0)
1049  op->attacktype = op->arch->clone.attacktype;
1050 
1051 
1052  /* First block is for encumbrance of the player */
1053 
1054  /* The check for FREE_PLAYER_LOAD_PERCENT < 1.0 is really a safety. One would
1055  * think that it should never be the case if that is set to 1.0, that carrying
1056  * would be above the limit. But it could be if character is weakened and
1057  * was otherwise at limit. Without that safety, could get divide by zeros.
1058  */
1060  && (FREE_PLAYER_LOAD_PERCENT < 1.0)) {
1061  int extra_weight = op->carrying-get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT;
1062 
1063  character_load = (float)extra_weight/(float)(get_weight_limit(op->stats.Str)*(1.0-FREE_PLAYER_LOAD_PERCENT));
1064 
1065  /* character_load is used for weapon speed below, so sanitize value */
1066  if (character_load >= 1.0)
1067  character_load = 1.0;
1068 
1069  /* If a character is fully loaded, they will always get cut down to min
1070  * speed no matter what their dex. Note that magic is below, so
1071  * still helps out.
1072  */
1073  if (op->speed > MAX_PLAYER_SPEED)
1074  op->speed -= character_load*(op->speed-MIN_PLAYER_SPEED);
1075  else
1076  op->speed -= character_load*(MAX_PLAYER_SPEED-MIN_PLAYER_SPEED);
1077  }
1078 
1079  /* This block is for weapon speed */
1080  op->weapon_speed = BASE_WEAPON_SPEED+get_speed_bonus(op->stats.Dex)-weapon_speed/20.0+added_speed/10.0;
1081  if (wc_obj) {
1082  op->weapon_speed += 0.005*wc_obj->level;
1083  } else
1084  op->weapon_speed += 0.005*op->level;
1085 
1086  /* character_load=1.0 means character is fully loaded, 0.0 is unloaded. Multiplying
1087  * by 0.2 for penalty is purely arbitrary, but slows things down without completely
1088  * stopping them.
1089  */
1090  op->weapon_speed -= character_load*0.2;
1091 
1092  if (op->weapon_speed < 0.05)
1093  op->weapon_speed = 0.05;
1094 
1095  /* It is quite possible that a player's spell costing might have changed,
1096  * so we will check that now.
1097  */
1099 }
1120 void fix_object(object *op) {
1121  int i;
1122  float max = 9, added_speed = 0, speed_reduce_from_disease = 1;
1123  int weapon_speed = 0;
1124  int best_wc = 0, best_ac = 0, wc = 0, ac = 0;
1125  int prot[NROFATTACKS], vuln[NROFATTACKS], potion_resist[NROFATTACKS];
1126  const object *grace_obj = NULL, *mana_obj = NULL, *wc_obj = NULL;
1127 
1128  /* First task is to clear all the values back to their original values */
1129  if (op->type == PLAYER) {
1130  for (i = 0; i < NUM_STATS; i++) {
1131  set_attr_value(&(op->stats), i, get_attr_value(&(op->contr->orig_stats), i));
1132  set_attr_value(&(op->contr->applied_stats), i, 0);
1133  }
1135  op->contr->encumbrance = 0;
1136 
1137  op->attacktype = 0;
1138  op->contr->digestion = 0;
1139  op->contr->gen_hp = 0;
1140  op->contr->gen_sp = 0;
1141  op->contr->gen_grace = 0;
1142  op->contr->gen_sp_armour = 10;
1143  op->contr->item_power = 0;
1144 
1145  /* Don't clobber all the range_ values. range_golem otherwise
1146  * gets reset for no good reason, and we don't want to reset
1147  * range_magic (what spell is readied). These three below
1148  * well get filled in based on what the player has equipped.
1149  */
1150  op->contr->ranges[range_bow] = NULL;
1151  op->contr->ranges[range_misc] = NULL;
1152  op->contr->ranges[range_skill] = NULL;
1153  } /* If player */
1154  memcpy(op->body_used, op->body_info, sizeof(op->body_info));
1155 
1156  if (op->slaying != NULL) {
1157  free_string(op->slaying);
1158  op->slaying = NULL;
1159  }
1160  if (!QUERY_FLAG(op, FLAG_WIZ)) {
1161  CLEAR_FLAG(op, FLAG_XRAYS);
1163  }
1164 
1166  CLEAR_FLAG(op, FLAG_STEALTH);
1167  CLEAR_FLAG(op, FLAG_BLIND);
1169  if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_SPELL))
1171  if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_MISSILE))
1173  if (!QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
1174  CLEAR_FLAG(op, FLAG_UNDEAD);
1175  if (!QUERY_FLAG(&op->arch->clone, FLAG_SEE_IN_DARK))
1177  CLEAR_FLAG(op, FLAG_PROBE);
1178 
1179  op->path_attuned = op->arch->clone.path_attuned;
1181  op->path_denied = op->arch->clone.path_denied;
1182  op->glow_radius = op->arch->clone.glow_radius;
1183  op->move_type = op->arch->clone.move_type;
1184  op->chosen_skill = NULL;
1185 
1186  /* initializing resistances from the values in player/monster's
1187  * archetype clone
1188  */
1189  memcpy(&op->resist, &op->arch->clone.resist, sizeof(op->resist));
1190 
1191  for (i = 0; i < NROFATTACKS; i++) {
1192  if (op->resist[i] > 0)
1193  prot[i] = op->resist[i], vuln[i] = 0;
1194  else
1195  vuln[i] = -(op->resist[i]), prot[i] = 0;
1196  potion_resist[i] = 0;
1197  }
1198 
1199  wc = op->arch->clone.stats.wc;
1200  op->stats.dam = op->arch->clone.stats.dam;
1201 
1202  /* for players which cannot use armour, they gain AC -1 per 3 levels,
1203  * plus a small amount of physical resist, those poor suckers. ;)
1204  * the fact that maxlevel is factored in could be considered sort of bogus -
1205  * we should probably give them some bonus and cap it off - otherwise,
1206  * basically, if a server updates its max level, these playes may find
1207  * that their protection from physical goes down
1208  */
1209  if (!QUERY_FLAG(op, FLAG_USE_ARMOUR) && op->type == PLAYER) {
1210  ac = MAX(-10, op->arch->clone.stats.ac-op->level/3);
1211  prot[ATNR_PHYSICAL] += ((100-prot[AT_PHYSICAL])*(80*op->level/settings.max_level))/100;
1212  } else
1213  ac = op->arch->clone.stats.ac;
1214 
1215  op->stats.luck = op->arch->clone.stats.luck;
1216  op->speed = op->arch->clone.speed;
1217 
1218  /* OK - we've reset most all the objects attributes to sane values.
1219  * now go through and make adjustments for what the player has equipped.
1220  */
1221 
1222  FOR_INV_PREPARE(op, tmp) {
1223  /* See note in map.c:update_position about making this additive
1224  * since light sources are never applied, need to put check here.
1225  */
1226  if (tmp->glow_radius > op->glow_radius)
1227  op->glow_radius = tmp->glow_radius;
1228 
1229  /* This happens because apply_potion calls change_abil with the potion
1230  * applied so we can tell the player what chagned. But change_abil
1231  * then calls this function.
1232  */
1233  if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == POTION)
1234  continue;
1235 
1236  /* For some things, we don't care what is equipped */
1237  if (tmp->type == SKILL) {
1238  /* Want to take the highest skill here. */
1239  if (IS_MANA_SKILL(tmp->subtype)) {
1240  if (!mana_obj)
1241  mana_obj = tmp;
1242  else if (tmp->level > mana_obj->level)
1243  mana_obj = tmp;
1244  }
1245  if (IS_GRACE_SKILL(tmp->subtype)) {
1246  if (!grace_obj)
1247  grace_obj = tmp;
1248  else if (tmp->level > grace_obj->level)
1249  grace_obj = tmp;
1250  }
1251  }
1252 
1253  /* Container objects are not meant to adjust a players, but other applied
1254  * objects need to make adjustments.
1255  * This block should handle all player specific changes
1256  * The check for Praying is a bit of a hack - god given bonuses are put
1257  * in the praying skill, and the player should always get those.
1258  * It also means we need to put in additional checks for applied below,
1259  * because the skill shouldn't count against body positions being used
1260  * up, etc.
1261  */
1262  if ((QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type != CONTAINER && tmp->type != CLOSE_CON)
1263  || (tmp->type == SKILL && tmp->subtype == SK_PRAYING)) {
1264  if (op->type == PLAYER) {
1265  if (tmp->type == BOW)
1266  op->contr->ranges[range_bow] = tmp;
1267 
1268  if (tmp->type == WAND || tmp->type == ROD)
1269  op->contr->ranges[range_misc] = tmp;
1270 
1271  for (i = 0; i < NUM_STATS; i++) {
1272  int8_t value;
1273 
1274  value = get_attr_value(&(tmp->stats), i);
1275  change_attr_value(&(op->stats), i, value);
1276  if (strcmp(tmp->arch->clone.name, ARCH_DEPLETION) != 0)
1277  change_attr_value(&(op->contr->applied_stats), i, value);
1278  }
1279 
1280  /* For this temporary calculation, allow wider range of stat - if we have
1281  * having that gives +5 and different object that gives -5 and stat
1282  * is maxed, we don't want different results based on order of
1283  * inventory.
1284  */
1285  check_stat_bounds(&(tmp->stats), -settings.max_stat, 2*settings.max_stat);
1286 
1287  /* these are the items that currently can change digestion, regeneration,
1288  * spell point recovery and mana point recovery. Seems sort of an arbitary
1289  * list, but other items store other info into stats array.
1290  */
1291  switch (tmp->type)
1292  {
1293  case WEAPON:
1294  case ARMOUR:
1295  case HELMET:
1296  case SHIELD:
1297  case RING:
1298  case BOOTS:
1299  case GLOVES:
1300  case AMULET:
1301  case GIRDLE:
1302  case BRACERS:
1303  case CLOAK:
1304  case DISEASE:
1305  case FORCE:
1306  case SKILL:
1307  op->contr->digestion += tmp->stats.food;
1308  op->contr->gen_hp += tmp->stats.hp;
1309  op->contr->gen_sp += tmp->stats.sp;
1310  op->contr->gen_grace += tmp->stats.grace;
1311  op->contr->gen_sp_armour += tmp->gen_sp_armour;
1312  /*FALLTHROUGH*/
1313 
1314  /* Bow and skill utils need to update item_power specifically.
1315  * This should fix bug #648
1316  * Daniel Hawkins 2017-08-09
1317  */
1318  case BOW:
1319  case SKILL_TOOL:
1320  op->contr->item_power += tmp->item_power;
1321  break;
1322  }
1323  } /* if this is a player */
1324 
1325  /* Update slots used for items */
1326  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1327  for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1328  op->body_used[i] += tmp->body_info[i];
1329  }
1330 
1331  if (tmp->type == SYMPTOM && tmp->last_sp) {
1332  /* Should take the worst disease of the bunch */
1333  if (((float)tmp->last_sp/100.0) < speed_reduce_from_disease)
1334  speed_reduce_from_disease = (float)tmp->last_sp/100.0;
1335  }
1336 
1337  /* Pos. and neg. protections are counted seperate (-> pro/vuln).
1338  * (Negative protections are calculated extactly like positive.)
1339  * Resistance from potions are treated special as well. If there's
1340  * more than one potion-effect, the bigger prot.-value is taken.
1341  */
1342  if (tmp->type != POTION) {
1343  for (i = 0; i < NROFATTACKS; i++) {
1344  /* Potential for cursed potions, in which case we just can use
1345  * a straight MAX, as potion_resist is initialized to zero.
1346  */
1347  if (tmp->type == POTION_RESIST_EFFECT) {
1348  if (potion_resist[i])
1349  potion_resist[i] = MAX(potion_resist[i], tmp->resist[i]);
1350  else
1351  potion_resist[i] = tmp->resist[i];
1352  } else if (tmp->resist[i] > 0)
1353  prot[i] += ((100-prot[i])*tmp->resist[i])/100;
1354  else if (tmp->resist[i] < 0)
1355  vuln[i] += ((100-vuln[i])*(-tmp->resist[i]))/100;
1356  }
1357  }
1358 
1359  /* There may be other things that should not adjust the attacktype */
1360  if (tmp->type != BOW && tmp->type != SYMPTOM)
1361  op->attacktype |= tmp->attacktype;
1362 
1363  op->path_attuned |= tmp->path_attuned;
1364  op->path_repelled |= tmp->path_repelled;
1365  op->path_denied |= tmp->path_denied;
1366  op->stats.luck += tmp->stats.luck;
1367  op->move_type |= tmp->move_type;
1368 
1369  if (QUERY_FLAG(tmp, FLAG_LIFESAVE))
1370  SET_FLAG(op, FLAG_LIFESAVE);
1371  if (QUERY_FLAG(tmp, FLAG_REFL_SPELL))
1373  if (QUERY_FLAG(tmp, FLAG_REFL_MISSILE))
1375  if (QUERY_FLAG(tmp, FLAG_STEALTH))
1376  SET_FLAG(op, FLAG_STEALTH);
1377  if (QUERY_FLAG(tmp, FLAG_XRAYS))
1378  SET_FLAG(op, FLAG_XRAYS);
1379  if (QUERY_FLAG(tmp, FLAG_BLIND))
1380  SET_FLAG(op, FLAG_BLIND);
1381  if (QUERY_FLAG(tmp, FLAG_SEE_IN_DARK))
1383  if (QUERY_FLAG(tmp, FLAG_PROBE))
1384  SET_FLAG(op, FLAG_PROBE);
1385 
1386  // Items can make the wielder confused.
1387  if (QUERY_FLAG(tmp, FLAG_CONFUSED))
1388  SET_FLAG(op, FLAG_CONFUSED);
1389 
1390  if (QUERY_FLAG(tmp, FLAG_UNDEAD) && !QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
1391  SET_FLAG(op, FLAG_UNDEAD);
1392 
1393  if (QUERY_FLAG(tmp, FLAG_MAKE_INVIS)) {
1395  op->invisible = 1;
1396  }
1397 
1398  if (tmp->stats.exp && tmp->type != SKILL) {
1399  added_speed += (float)tmp->stats.exp/3.0;
1400  }
1401 
1402  switch (tmp->type) {
1403  /* skills modifying the character -b.t. */
1404  /* for all skills and skill granting objects */
1405  case SKILL:
1406  if (!QUERY_FLAG(tmp, FLAG_APPLIED))
1407  break;
1408 
1409  if (IS_COMBAT_SKILL(tmp->subtype))
1410  wc_obj = tmp;
1411 
1412  if (op->chosen_skill) {
1413  LOG(llevDebug, "fix_object, op %s has multiple skills applied\n", op->name);
1414  }
1415  op->chosen_skill = tmp;
1416  if (tmp->stats.dam > 0) { /* skill is a 'weapon' */
1417  if (!QUERY_FLAG(op, FLAG_READY_WEAPON))
1418  weapon_speed = (int)WEAPON_SPEED(tmp);
1419  if (weapon_speed < 0)
1420  weapon_speed = 0;
1421  op->stats.dam += tmp->stats.dam*(1+(op->chosen_skill->level/9));
1422  op->stats.dam += tmp->magic;
1423  }
1424  if (tmp->stats.wc)
1425  wc -= (tmp->stats.wc+tmp->magic);
1426 
1427  if (tmp->slaying != NULL) {
1428  if (op->slaying != NULL)
1429  free_string(op->slaying);
1430  add_refcount(op->slaying = tmp->slaying);
1431  }
1432 
1433  if (tmp->stats.ac)
1434  ac -= (tmp->stats.ac+tmp->magic);
1435  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1436  op->contr->encumbrance += (int)3*tmp->weight/1000;
1437  if (op->type == PLAYER)
1438  op->contr->ranges[range_skill] = op;
1439  break;
1440 
1441  case SKILL_TOOL:
1442  if (op->chosen_skill) {
1443  LOG(llevDebug, "fix_object, op %s has multiple skills applied\n", op->name);
1444  }
1445  op->chosen_skill = tmp;
1446  if (op->type == PLAYER)
1447  op->contr->ranges[range_skill] = op;
1448  break;
1449 
1450  case SHIELD:
1451  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1452  op->contr->encumbrance += (int)tmp->weight/2000;
1453  /* fall through */
1454  case RING:
1455  case AMULET:
1456  case GIRDLE:
1457  case HELMET:
1458  case BOOTS:
1459  case GLOVES:
1460  case CLOAK:
1461  if (tmp->stats.wc)
1462  wc -= tmp->stats.wc;
1463  if (tmp->stats.dam)
1464  op->stats.dam += (tmp->stats.dam+tmp->magic);
1465  if (tmp->stats.ac)
1466  ac -= (tmp->stats.ac+tmp->magic);
1467  break;
1468 
1469  case WEAPON:
1470  wc -= tmp->stats.wc;
1471  if (tmp->stats.ac && tmp->stats.ac+tmp->magic > 0)
1472  ac -= tmp->stats.ac+tmp->magic;
1473  op->stats.dam += (tmp->stats.dam+tmp->magic);
1474  weapon_speed = ((int)WEAPON_SPEED(tmp)*2-tmp->magic)/2;
1475  if (weapon_speed < 0)
1476  weapon_speed = 0;
1477  if (tmp->slaying != NULL) {
1478  if (op->slaying != NULL)
1479  free_string(op->slaying);
1480  add_refcount(op->slaying = tmp->slaying);
1481  }
1482  /* If there is desire that two handed weapons should do
1483  * extra strength damage, this is where the code should
1484  * go.
1485  */
1486  op->current_weapon = tmp;
1487  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1488  op->contr->encumbrance += (int)3*tmp->weight/1000;
1489  break;
1490 
1491  case ARMOUR: /* Only the best of these three are used: */
1492  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1493  op->contr->encumbrance += (int)tmp->weight/1000;
1494 
1495  /* ARMOUR falls through to here */
1496  /* fall through */
1497  case BRACERS:
1498  case FORCE:
1499  // Code simplification to reduce branching -- we don't need to sub/add ac and wc all the time.
1500  // Daniel Hawkins 2018-05-28
1501  if (tmp->stats.wc) {
1502  // Since we are alreay here, make sure wc stacking also occurs for serpentman players.
1503  if (tmp->type == BRACERS && op->type == PLAYER && op->arch->name && strcmp(op->arch->name, "serpentman_player") == 0)
1504  {
1505  // Apply ac from bracers directly.
1506  // This also grants the side effect that armor and bracer ac are separate for serpentmen,
1507  // But that should be better than the extra bracers being mostly useless.
1508  wc -= tmp->stats.wc;
1509  }
1510  else if (best_wc < tmp->stats.wc) {
1511  wc += best_wc;
1512  best_wc = tmp->stats.wc;
1513  wc -= tmp->stats.wc;
1514  }
1515  }
1516  if (tmp->stats.ac) {
1517  /*
1518  * If we have a serpentman player, then we do bracers differently
1519  * to allow for both bracers they equip to apply to ac, instead of only the best.
1520  *
1521  * Daniel Hawkins 2018-05-28
1522  */
1523  if (tmp->type == BRACERS && op->type == PLAYER && op->arch->name && strcmp(op->arch->name, "serpentman_player") == 0)
1524  {
1525  // Apply ac from bracers directly.
1526  // This also grants the side effect that armor and bracer ac are separate for serpentmen,
1527  // But that should be better than the extra bracers being mostly useless.
1528  ac -= tmp->stats.ac+tmp->magic;
1529  }
1530  else if (best_ac < tmp->stats.ac+tmp->magic) {
1531  ac += best_ac; /* Remove last bonus */
1532  best_ac = tmp->stats.ac+tmp->magic;
1533  ac -= (tmp->stats.ac+tmp->magic);
1534  }
1535  }
1536  if (tmp->stats.dam && tmp->type == BRACERS)
1537  op->stats.dam += (tmp->stats.dam+tmp->magic);
1538  if (ARMOUR_SPEED(tmp) && ARMOUR_SPEED(tmp)/10.0 < max)
1539  max = ARMOUR_SPEED(tmp)/10.0;
1540  break;
1541  } /* switch tmp->type */
1542  } /* item is equipped */
1543  } FOR_INV_FINISH(); /* for loop of items */
1544 
1545  /* We've gone through all the objects the player has equipped. For many things, we
1546  * have generated intermediate values which we now need to assign.
1547  */
1548 
1549  /* 'total resistance = total protections - total vulnerabilities'.
1550  * If there is an uncursed potion in effect, granting more protection
1551  * than that, we take: 'total resistance = resistance from potion'.
1552  * If there is a cursed (and no uncursed) potion in effect, we take
1553  * 'total resistance = vulnerability from cursed potion'.
1554  */
1555  for (i = 0; i < NROFATTACKS; i++) {
1556  op->resist[i] = prot[i]-vuln[i];
1557  if (potion_resist[i]
1558  && ((potion_resist[i] > op->resist[i]) || (potion_resist[i] < 0)))
1559  op->resist[i] = potion_resist[i];
1560  }
1561 
1562  fix_player(op, &ac, &wc, grace_obj, mana_obj, wc_obj, weapon_speed, added_speed);
1563 
1564  op->speed = op->speed*speed_reduce_from_disease;
1565 
1566  /* Max is determined by armour */
1567  if (op->speed > max)
1568  op->speed = max;
1569 
1570  op->speed += added_speed/10.0;
1571 
1572 
1573  /* Put a lower limit on speed. Note with this speed, you move once every
1574  * 20 ticks or so. This amounts to once every 3 seconds of realtime.
1575  */
1576  if (op->speed < 0.05 && op->type == PLAYER)
1577  op->speed = 0.05;
1578  /*
1579  * A lower limit should also apply to monsters. By ensuring speeds are
1580  * loaded in as positive, we can properly do this. Otherwise, slow effects
1581  * either push the monster's speed to be more negative (if we leave the input
1582  * speed as negative) or can reduce the speed by more than the monster's speed,
1583  * making it turn negative (if we load speeds as positive always).
1584  *
1585  * For whatever reason, op->type is 0 for some monsters, making FLAG_MONSTER
1586  * the useful information that indicates whether it is a monster or not.
1587  *
1588  * MIN_ACTIVE_SPEED is super low, so make our speed threshold be about .005 instead
1589  */
1590  if (op->speed < MIN_ACTIVE_SPEED*500 && QUERY_FLAG(op, FLAG_MONSTER)) {
1591  // If added_speed is less than zero, we're probably working with a slow effect.
1592  if (added_speed >= 0)
1593  LOG(llevInfo, "fix_object: Monster %s has negative speed of %f.\n",
1594  op->name ? op->name : "(null)", op->speed);
1595  op->speed = MIN_ACTIVE_SPEED*500;
1596  }
1597 
1598  /* I want to limit the power of small monsters with big weapons: */
1599  if (op->type != PLAYER
1600  && op->arch != NULL
1601  && op->stats.dam > op->arch->clone.stats.dam*3)
1602  op->stats.dam = op->arch->clone.stats.dam*3;
1603 
1604  /* Prevent overflows of wc - best you can get is ABS(120) - this
1605  * should be more than enough - remember, AC is also in 8 bits,
1606  * so its value is the same.
1607  */
1608  if (wc > 120)
1609  wc = 120;
1610  else if (wc < -120)
1611  wc = -120;
1612  op->stats.wc = wc;
1613 
1614  if (ac > 120)
1615  ac = 120;
1616  else if (ac < -120)
1617  ac = -120;
1618  op->stats.ac = ac;
1619 
1620  /* if for some reason the creature doesn't have any move type,
1621  * give them walking as a default.
1622  * The second case is a special case - to more closely mimic the
1623  * old behaviour - if your flying, your not walking - just
1624  * one or the other.
1625  */
1626  if (op->move_type == 0)
1627  op->move_type = MOVE_WALK;
1628  else if (op->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
1629  op->move_type &= ~MOVE_WALK;
1630 
1631  object_update_speed(op);
1632 }
1633 
1646 int allowed_class(const object *op) {
1647  return op->stats.Dex > 0
1648  && op->stats.Str > 0
1649  && op->stats.Con > 0
1650  && op->stats.Int > 0
1651  && op->stats.Wis > 0
1652  && op->stats.Pow > 0
1653  && op->stats.Cha > 0;
1654 }
1655 
1673 void set_dragon_name(object *pl, const object *abil, const object *skin) {
1674  int atnr = -1; /* attacknumber of highest level */
1675  int level = 0; /* highest level */
1676  int i;
1677 
1678  /* Perhaps do something more clever? */
1679  if (!abil || !skin)
1680  return;
1681 
1682  /* first, look for the highest level */
1683  for (i = 0; i < NROFATTACKS; i++) {
1684  if (atnr_is_dragon_enabled(i)
1685  && (atnr == -1 || abil->resist[i] > abil->resist[atnr])) {
1686  level = abil->resist[i];
1687  atnr = i;
1688  }
1689  }
1690 
1691  /* now if there are equals at highest level, pick the one with focus,
1692  or else at random */
1693  if (atnr_is_dragon_enabled(abil->stats.exp)
1694  && abil->resist[abil->stats.exp] >= level)
1695  atnr = abil->stats.exp;
1696 
1697  level = (int)(level/5.);
1698 
1699  /* now set the new title */
1700  if (pl->contr != NULL) {
1701  player_set_dragon_title(pl->contr, level, attacks[atnr], skin->resist[atnr]);
1702  }
1703 }
1704 
1713 static void dragon_level_gain(object *who) {
1714  object *abil = NULL; /* pointer to dragon ability force*/
1715  object *skin = NULL; /* pointer to dragon skin force*/
1716 
1717  /* now grab the 'dragon_ability'-forces from the player's inventory */
1718  abil = object_find_by_type_and_arch_name(who, FORCE, "dragon_ability_force");
1719  skin = object_find_by_type_and_arch_name(who, FORCE, "dragon_skin_force");
1720  /* if the force is missing -> bail out */
1721  if (abil == NULL)
1722  return;
1723 
1724  /* The ability_force keeps track of maximum level ever achieved.
1725  * New abilties can only be gained by surpassing this max level
1726  */
1727  if (who->level > abil->level) {
1728  /* increase our focused ability */
1729  int lev = ++(abil->resist[abil->stats.exp]);
1730 
1731  if (lev > 0) {
1732  /* try to hand out a new ability-gift
1733  * if not the right level, this will handout nothing.
1734  */
1735  dragon_ability_gain(who, (int)abil->stats.exp, lev);
1736  }
1737 
1738  if (abil->last_eat > 0 && atnr_is_dragon_enabled(abil->last_eat)) {
1739  /* apply new ability focus */
1741  "Your metabolism now focuses on %s!",
1742  change_resist_msg[abil->last_eat]);
1743 
1744  abil->stats.exp = abil->last_eat;
1745  abil->last_eat = 0;
1746  }
1747 
1748  abil->level = who->level;
1749  }
1750 
1751  /* last but not least, set the new title for the dragon */
1752  set_dragon_name(who, abil, skin);
1753 }
1754 
1773 object *give_skill_by_name(object *op, const char *skill_name) {
1774  object *skill_obj;
1775  archetype *skill_arch;
1776 
1777  skill_arch = get_archetype_by_skill_name(skill_name, SKILL);
1778  if (!skill_arch) {
1779  LOG(llevError, "add_player_exp: couldn't find skill %s\n", skill_name);
1780  return NULL;
1781  }
1782  skill_obj = arch_to_object(skill_arch); /* never returns NULL. */
1783 
1784  /* clear the flag - exp goes into this bucket, but player
1785  * still doesn't know it.
1786  */
1787  CLEAR_FLAG(skill_obj, FLAG_CAN_USE_SKILL);
1788  skill_obj->stats.exp = 0;
1789  skill_obj->level = 1;
1790  object_insert_in_ob(skill_obj, op);
1791  if (op->contr) {
1792  link_player_skills(op);
1793  }
1794  return skill_obj;
1795 }
1796 
1813 void player_lvl_adj(object *who, object *op) {
1814  char buf[MAX_BUF];
1815 
1816  assert(who);
1817 
1818  if (!op) /* when rolling stats */
1819  op = who;
1820 
1821  if (op->level < settings.max_level && op->stats.exp >= level_exp(op->level+1, who->expmul)) {
1822  do{
1823  op->level++;
1824 
1825  if (op != NULL && op == who && op->stats.exp > 1 && is_dragon_pl(who))
1826  dragon_level_gain(who);
1827 
1828  /* Only roll these if it is the player (who) that gained the level */
1829  if (op == who && (who->level < 11) && who->type == PLAYER) {
1830  who->contr->levhp[who->level] = die_roll(2, 4, who, PREFER_HIGH)+1;
1831  who->contr->levsp[who->level] = die_roll(2, 3, who, PREFER_HIGH);
1832  who->contr->levgrace[who->level] = die_roll(2, 2, who, PREFER_HIGH)-1;
1833  }
1834 
1835  fix_object(who); // TODO: Call this only once per function call?
1836  if (op->level > 1) {
1837  if (op->type != PLAYER)
1838  snprintf(buf, sizeof(buf), "You are now level %d in the %s skill.", op->level, op->name);
1839  else
1840  snprintf(buf, sizeof(buf), "You are now level %d.", op->level);
1841 
1843  }
1844  } while (op->level < settings.max_level && op->stats.exp >= level_exp(op->level+1, who->expmul)); /* To increase more levels */
1845  } else if (op->level > 1 && op->stats.exp < level_exp(op->level, who->expmul)) {
1846  do{
1847  op->level--;
1848  fix_object(who); // TODO: Call this only once per function call?
1849  if (op->type != PLAYER)
1850  snprintf(buf, sizeof(buf), "You are now level %d in the %s skill.", op->level, op->name);
1851  else
1852  snprintf(buf, sizeof(buf), "You are now level %d.", op->level);
1853 
1855  } while (op->level > 1 && op->stats.exp < level_exp(op->level, who->expmul)); /* To decrease more levels */
1856  }
1857 }
1858 
1868 int64_t level_exp(int level, double expmul) {
1869  if (level > settings.max_level)
1870  return expmul*levels[settings.max_level];
1871  return expmul*levels[level];
1872 }
1873 
1880 int exp_level(int64_t exp) {
1881  int level = 1;
1882  while ( level < settings.max_level && levels[level+1] <= exp )
1883  ++level;
1884  return level;
1885 }
1886 
1897 void calc_perm_exp(object *op) {
1898  if (op->total_exp < op->stats.exp)
1899  op->total_exp = op->stats.exp;
1900 
1901  /* Cap permanent experience. */
1902  if (op->total_exp < 0)
1903  op->total_exp = 0;
1904  else if (op->total_exp > MAX_EXPERIENCE * 100 / settings.permanent_exp_ratio)
1906 }
1907 
1915 object* find_applied_skill_by_name(const object* op, const char* name) {
1916  for (int i = 0; i < MAX_SKILLS; i++) {
1917  if (op->contr->last_skill_ob[i] != NULL) {
1918  // Skill objects can be removed without updating last_skill_ob. Clean
1919  // them up here if that's the case.
1920  if (QUERY_FLAG(op->contr->last_skill_ob[i], FLAG_REMOVED)) {
1921  LOG(llevDebug, "pruning removed object from last_skill_ob\n");
1922  op->contr->last_skill_ob[i] = NULL;
1923  continue;
1924  }
1925 
1926  if (op->contr->last_skill_ob[i]->skill != NULL) {
1927  if (!strcmp(op->contr->last_skill_ob[i]->skill, name)) {
1928  return op->contr->last_skill_ob[i];
1929  }
1930  } else {
1931  LOG(llevError,
1932  "%s's skill object %s does not have a skill name\n",
1933  op->name, op->contr->last_skill_ob[i]->name);
1934  }
1935  }
1936  }
1937  return NULL;
1938 }
1939 
1954 static void add_player_exp(object *op, int64_t exp, const char *skill_name, int flag) {
1955  object *skill_obj = NULL;
1956  int64_t limit, exp_to_add;
1957  int64_t added_skill_exp, added_skill_total_exp;
1958 
1959  /* prevents some forms of abuse. */
1960  if (op->contr->braced)
1961  exp = exp/5;
1962 
1963  /* Try to find the matching skill.
1964  * We do a shortcut/time saving mechanism first - see if it matches
1965  * chosen_skill. This means we don't need to search through
1966  * the players inventory.
1967  */
1968  if (skill_name) {
1969  if (op->chosen_skill
1970  && op->chosen_skill->type == SKILL
1971  && !strcmp(skill_name, op->chosen_skill->skill))
1972  skill_obj = op->chosen_skill;
1973  else {
1974  skill_obj = find_applied_skill_by_name(op, skill_name);
1975 
1976  /* Player doesn't have the skill. Check to see what to do, and give
1977  * it to the player if necessary
1978  */
1979  if (!skill_obj) {
1980  if (flag == SK_EXP_NONE)
1981  return;
1982  else if (flag == SK_EXP_ADD_SKILL)
1983  skill_obj = give_skill_by_name(op, skill_name);
1984  }
1985  }
1986  }
1987 
1988  /* Basically, you can never gain more experience in one shot
1989  * than half what you need to gain for next level.
1990  */
1991  exp_to_add = exp;
1992  /*
1993  * Make sure we aren't trying to go backwards when we hit maximum level,
1994  * but make sure we can still add to our permanent experience.
1995  *
1996  * -- Daniel Hawkins 2015-05-24
1997  */
1998  if (op->level == settings.max_level)
1999  limit = levels[op->level] / 2;
2000  else
2001  limit = (levels[op->level+1]-levels[op->level])/2;
2002 
2003  if (exp_to_add > limit)
2004  exp_to_add = limit;
2005 
2006  if (skill_obj) {
2007  exp_to_add = exp;
2008  /*
2009  * Make sure we aren't trying to go backwards when we hit maximum level,
2010  * but make sure we can still add to our permanent experience.
2011  *
2012  * -- Daniel Hawkins 2015-05-24
2013  */
2014  if (skill_obj->level == settings.max_level)
2015  limit = levels[skill_obj->level] / 2;
2016  else
2017  limit = (levels[skill_obj->level+1]-levels[skill_obj->level])/2;
2018 
2019  if (exp_to_add > limit)
2020  exp_to_add = limit;
2021  added_skill_exp = skill_obj->stats.exp;
2022  ADD_EXP(skill_obj->stats.exp, exp_to_add);
2023  added_skill_exp = skill_obj->stats.exp - added_skill_exp;
2025  added_skill_total_exp = skill_obj->total_exp;
2026  ADD_TOTALEXP(skill_obj->total_exp, exp_to_add);
2027  added_skill_total_exp = skill_obj->total_exp - added_skill_total_exp;
2028  calc_perm_exp(skill_obj);
2029  }
2030  player_lvl_adj(op, skill_obj);
2031  }
2032  else {
2033  added_skill_exp = added_skill_total_exp = exp_to_add;
2034  }
2035 
2036  ADD_EXP(op->stats.exp, (float)added_skill_exp*(skill_obj ? skill_obj->expmul : 1));
2038  ADD_TOTALEXP(op->total_exp, (float)added_skill_total_exp*(skill_obj ? skill_obj->expmul : 1));
2039  calc_perm_exp(op);
2040  }
2041 
2042  player_lvl_adj(op, NULL);
2043 }
2044 
2060 int64_t check_exp_loss(const object *op, int64_t exp) {
2061  int64_t del_exp;
2062 
2063  if (exp > op->stats.exp)
2064  exp = op->stats.exp;
2066  del_exp = (op->stats.exp-PERM_EXP(op->total_exp))*PERM_EXP_MAX_LOSS_RATIO;
2067  if (del_exp < 0)
2068  del_exp = 0;
2069  if (exp > del_exp)
2070  exp = del_exp;
2071  }
2072  return exp;
2073 }
2074 
2085 int64_t check_exp_adjust(const object *op, int64_t exp) {
2086  if (exp < 0)
2087  return check_exp_loss(op, exp);
2088  else
2089  return MIN(exp, MAX_EXPERIENCE-op->stats.exp);
2090 }
2091 
2114 static void subtract_player_exp(object *op, int64_t exp, const char *skill, int flag) {
2115  float fraction = (float)exp/(float)op->stats.exp;
2116  int64_t del_exp;
2117 
2118  FOR_INV_PREPARE(op, tmp)
2119  if (tmp->type == SKILL && tmp->stats.exp) {
2120  if (flag == SK_SUBTRACT_SKILL_EXP && skill && !strcmp(tmp->skill, skill)) {
2121  del_exp = check_exp_loss(tmp, exp);
2122  tmp->stats.exp -= del_exp;
2123  player_lvl_adj(op, tmp);
2124  } else if (flag != SK_SUBTRACT_SKILL_EXP) {
2125  /* only want to process other skills if we are not trying
2126  * to match a specific skill.
2127  */
2128  del_exp = check_exp_loss(tmp, tmp->stats.exp*fraction);
2129  tmp->stats.exp -= del_exp;
2130  player_lvl_adj(op, tmp);
2131  }
2132  }
2133  FOR_INV_FINISH();
2134  if (flag != SK_SUBTRACT_SKILL_EXP) {
2135  del_exp = check_exp_loss(op, exp);
2136  op->stats.exp -= del_exp;
2137  player_lvl_adj(op, NULL);
2138  }
2139 }
2140 
2162 void change_exp(object *op, int64_t exp, const char *skill_name, int flag) {
2163  /* safety */
2164  if (!op) {
2165  LOG(llevError, "change_exp() called for null object!\n");
2166  return;
2167  }
2168 
2169  /* if no change in exp, just return - most of the below code
2170  * won't do anything if the value is 0 anyways.
2171  */
2172  if (exp == 0)
2173  return;
2174 
2175  /* Monsters are easy - we just adjust their exp - we
2176  * don't adjust level, since in most cases it is unrelated to
2177  * the exp they have - the monsters exp represents what its
2178  * worth.
2179  */
2180  if (op->type != PLAYER && op->type != WEAPON) {
2181  /* Sanity check */
2182  if (!QUERY_FLAG(op, FLAG_ALIVE))
2183  return;
2184 
2185  /* reset exp to max allowed value. We subtract from
2186  * MAX_EXPERIENCE to prevent overflows. If the player somehow has
2187  * more than max exp, just return.
2188  */
2189  if (exp > 0 && (op->stats.exp > (MAX_EXPERIENCE-exp))) {
2190  exp = MAX_EXPERIENCE-op->stats.exp;
2191  if (exp < 0)
2192  return;
2193  }
2194 
2195  op->stats.exp += exp;
2196  } else if (op->type == WEAPON) { /* Weapons -- this allows us to make magic weapons that get stronger the more they are used. */
2197  // Handle adding exp -- Don't use level because other stuff already uses that.
2198  // The caller should determine what percentage of base exp this is.
2199  ADD_TOTALEXP(op->total_exp, exp);
2200  if (exp > 0) {
2201  // Check for a level-up
2202  while (level_exp(op->item_power+1, 1) < op->total_exp) {
2203  ++(op->item_power);
2204  }
2205  } else { /* Removing exp allows for the weapon's power to be reset if needed. */
2206  // Recalculate level
2207  while (level_exp(op->item_power, 1) > op->total_exp) {
2208  --(op->item_power);
2209  }
2210  }
2211  } else { /* Players only */
2212  if (exp > 0)
2213  add_player_exp(op, exp, skill_name, flag);
2214  else
2215  subtract_player_exp(op, FABS(exp), skill_name, flag);
2216  }
2217 }
2218 
2227 void apply_death_exp_penalty(object *op) {
2228  int64_t loss;
2229  int64_t percentage_loss; /* defined by the setting 'death_penalty_percent' */
2230  int64_t level_loss; /* defined by the setting 'death_penalty_levels */
2231 
2232  FOR_INV_PREPARE(op, tmp)
2233  if (tmp->type == SKILL && tmp->stats.exp) {
2234  percentage_loss = tmp->stats.exp*settings.death_penalty_ratio/100;
2235  level_loss = tmp->stats.exp-levels[MAX(0, tmp->level-settings.death_penalty_level)];
2236 
2237  /* With the revised exp system, you can get cases where
2238  * losing several levels would still require that you have more
2239  * exp than you currently have - this is true if the levels
2240  * tables is a lot harder.
2241  */
2242  if (level_loss < 0)
2243  level_loss = 0;
2244 
2245  loss = check_exp_loss(tmp, MIN(level_loss, percentage_loss));
2246 
2247  tmp->stats.exp -= loss;
2248  player_lvl_adj(op, tmp);
2249  }
2250  FOR_INV_FINISH();
2251 
2252  percentage_loss = op->stats.exp*settings.death_penalty_ratio/100;
2253  level_loss = op->stats.exp-levels[MAX(0, op->level-settings.death_penalty_level)];
2254  if (level_loss < 0)
2255  level_loss = 0;
2256  loss = check_exp_loss(op, MIN(level_loss, percentage_loss));
2257 
2258  op->stats.exp -= loss;
2259  player_lvl_adj(op, NULL);
2260 }
2261 
2276 int did_make_save(const object *op, int level, int bonus) {
2277  if (level > MAX_SAVE_LEVEL)
2278  level = MAX_SAVE_LEVEL;
2279 
2280  if ((random_roll(1, 20, op, PREFER_HIGH)+bonus) < savethrow[level])
2281  return 0;
2282  return 1;
2283 }
2284 
2306 void share_exp(object *op, int64_t exp, const char *skill, int flag) {
2307  int shares = 0, count = 0;
2308  player *pl;
2309  partylist *party;
2310 
2311  if (op->type != PLAYER || op->contr->party == NULL) {
2312  change_exp(op, exp, skill, 0);
2313  return;
2314  }
2315 
2316  party = op->contr->party;
2317 
2318  for (pl = first_player; pl != NULL; pl = pl->next) {
2319  if (party && pl->ob->contr->party == party && on_same_map(pl->ob, op)) {
2320  count++;
2321  shares += (pl->ob->level+4);
2322  }
2323  }
2324 
2325  assert(shares > 0);
2326 
2327  if (count == 1 || shares > exp)
2328  change_exp(op, exp, skill, flag);
2329  else {
2330  int64_t share = exp/shares, given = 0, nexp;
2331  for (pl = first_player; pl != NULL; pl = pl->next) {
2332  if (party && pl->ob->contr->party == party && on_same_map(pl->ob, op)) {
2333  nexp = (pl->ob->level+4)*share;
2334  change_exp(pl->ob, nexp, skill, SK_EXP_TOTAL);
2335  given += nexp;
2336  }
2337  }
2338  exp -= given;
2339  /* give any remainder to the player */
2340  change_exp(op, exp, skill, flag);
2341  }
2342 }
2343 
2344 int get_cha_bonus(int stat) {
2346 }
2347 
2348 int get_dex_bonus(int stat) {
2350 }
2351 
2352 int get_thaco_bonus(int stat) {
2354 }
2355 
2358 }
2359 
2360 int get_learn_spell(int stat) {
2362 }
2363 
2364 int get_cleric_chance(int stat) {
2366 }
2367 
2368 int get_turn_bonus(int stat) {
2370 }
2371 
2372 int get_dam_bonus(int stat) {
2374 }
2375 
2376 float get_speed_bonus(int stat) {
2378 }
2379 
2380 int get_fear_bonus(int stat) {
2382 }
2383 
2384 static float get_con_bonus(int stat) {
2386 }
2387 
2388 static float get_sp_bonus(int stat) {
2390 }
2391 
2392 static float get_grace_bonus(int stat) {
2394 }
2395 
2404 static size_t get_index(int stat, size_t max_index) {
2405  size_t index;
2406 
2407  if (stat < 0) {
2408  return 0;
2409  }
2410 
2411  index = (size_t)stat;
2412  return MIN(index, max_index);
2413 }
2414 
2432 static int load_table_int(int **bonuses, FILE *fp, char *bonus_name)
2433 {
2434  char buf[MAX_BUF], *cp;
2435  int on_stat = 0, tmp_bonus;
2436 
2437  *bonuses = calloc(settings.max_stat+1, sizeof(int));
2438 
2439  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2440  if (buf[0] == '#')
2441  continue;
2442 
2443  /* Skip over empty lines */
2444  if (buf[0] == '\n')
2445  continue;
2446 
2447  /* Do not care about opening brace */
2448  if (buf[0] == '{')
2449  continue;
2450 
2451  if (buf[0] == '}') {
2452  if ((on_stat-1) != settings.max_stat) {
2453  LOG(llevError,"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2454  on_stat, settings.max_stat, bonus_name);
2455  return 1;
2456  }
2457  else return 0;
2458  }
2459 
2460  /* If not any of the above values, must be the stat table,
2461  * or so we hope.
2462  */
2463  cp = buf;
2464  while (*cp != 0) {
2465  /* Skip over any non numbers */
2466  while (!isdigit(*cp) && *cp!='.' && *cp!='-' && *cp!='+' && *cp != 0)
2467  cp++;
2468 
2469  if (*cp == 0) break;
2470 
2471  tmp_bonus = atoi(cp);
2472 
2473  if (on_stat > settings.max_stat) {
2474  LOG(llevError,"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2475  buf, bonus_name);
2476  return 1;
2477  }
2478  (*bonuses)[on_stat] = tmp_bonus;
2479  on_stat++;
2480 
2481  /* Skip over any digits, as that is the number we just processed */
2482  while ((isdigit(*cp) || *cp=='-' || *cp=='+') && *cp != 0)
2483  cp++;
2484  }
2485  }
2486  /* This should never happen - we should always get the closing brace */
2487  LOG(llevError,"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2488  return 1;
2489 }
2490 
2508 static int load_table_float(float **bonuses, FILE *fp, char *bonus_name)
2509 {
2510  char buf[MAX_BUF], *cp;
2511  int on_stat = 0;
2512  float tmp_bonus;
2513 
2514  *bonuses = calloc(settings.max_stat+1, sizeof(float));
2515 
2516  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2517  if (buf[0] == '#')
2518  continue;
2519 
2520  /* Skip over empty lines */
2521  if (buf[0] == '\n')
2522  continue;
2523 
2524  /* Do not care about opening brace */
2525  if (buf[0] == '{')
2526  continue;
2527 
2528  if (buf[0] == '}') {
2529  if ((on_stat-1) != settings.max_stat) {
2530  LOG(llevError,"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2531  on_stat, settings.max_stat, bonus_name);
2532  return 1;
2533  }
2534  else return 0;
2535  }
2536 
2537  /* If not any of the above values, must be the stat table,
2538  * or so we hope.
2539  */
2540  cp = buf;
2541  while (*cp != 0) {
2542  /* Skip over any non numbers */
2543  while (!isdigit(*cp) && *cp!='.' && *cp!='-' && *cp!='+' && *cp != 0)
2544  cp++;
2545 
2546  if (*cp == 0) break;
2547 
2548  tmp_bonus = atof(cp);
2549 
2550  if (on_stat > settings.max_stat) {
2551  LOG(llevError,"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2552  buf, bonus_name);
2553  return 1;
2554  }
2555  (*bonuses)[on_stat] = tmp_bonus;
2556  on_stat++;
2557 
2558  /* Skip over any digits, as that is the number we just processed
2559  * since this is floats, also skip over any dots.
2560  */
2561  while ((isdigit(*cp) || *cp=='-' || *cp=='+' || *cp=='.') && *cp != 0)
2562  cp++;
2563  }
2564  }
2565  /* This should never happen - we should always get the closing brace */
2566  LOG(llevError,"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2567  return 1;
2568 }
2569 
2570 
2588 void init_stats(int reload) {
2589  char buf[MAX_BUF], *cp;
2590  int error=0, i, oldmax = settings.max_stat;
2591  FILE *fp;
2592  float *new_float_bonuses[NUM_FLOAT_BONUSES];
2593  int *new_int_bonuses[NUM_INT_BONUSES];
2594 
2595  snprintf(buf, sizeof(buf), "%s/stat_bonus", settings.confdir);
2596 
2597  memset(new_int_bonuses, 0, NUM_INT_BONUSES * sizeof(int));
2598  memset(new_float_bonuses, 0, NUM_FLOAT_BONUSES * sizeof(float));
2599 
2600  if ((fp = fopen(buf, "r")) == NULL) {
2601  LOG(llevError, "Fatal error: could not open experience table (%s)\n", buf);
2602  if (reload) return;
2603  else exit(1);
2604  }
2605  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2606  if (buf[0] == '#')
2607  continue;
2608 
2609  /* eliminate newline */
2610  if ((cp = strrchr(buf, '\n')) != NULL)
2611  *cp = '\0';
2612 
2613  /* Skip over empty lines */
2614  if (buf[0] == 0)
2615  continue;
2616 
2617  /* Skip over leading spaces */
2618  cp = buf;
2619  while (isspace(*cp) && *cp != 0)
2620  cp++;
2621 
2622  if (!strncasecmp(cp, "max_stat", 8)) {
2623  int newmax = atoi(cp+8);
2624 
2625  /* newmax must be at least MIN_STAT and we do not currently
2626  * cupport decrease max stat on the fly - why this might be possible,
2627  * bounds checking for all objects would be needed, potentionally resetting
2628  * them.
2629  * If this is a reload, then on error, we just return without doing work.
2630  * If this is initial load, having an invalid stat range is an error, so
2631  * exit the program.
2632  */
2633  if (newmax < MIN_STAT || newmax < settings.max_stat) {
2634  LOG(llevError, "Got invalid max_stat (%d) from stat_bonus file\n", newmax);
2635  fclose(fp);
2636  if (reload) return;
2637  else exit(1);
2638  }
2639  settings.max_stat = newmax;
2640  continue;
2641  }
2642  /* max_stat needs to be set before any of the bonus values - we
2643  * need to know how large to make the array.
2644  */
2645  if (settings.max_stat == 0) {
2646  LOG(llevError, "Got bonus line or otherwise unknown value before max stat! (%s)\n",
2647  buf);
2648  fclose(fp);
2649 
2650  if (reload) {
2651  return;
2652  } else {
2653  exit(1);
2654  }
2655  }
2656 
2657  for (i=0; i<NUM_INT_BONUSES; i++) {
2658  if (!strncasecmp(cp, int_bonus_names[i], strlen(int_bonus_names[i]))) {
2659  error = load_table_int(&new_int_bonuses[i], fp, cp);
2660  break;
2661  }
2662  }
2663  /* If we did not find a match in the int bonuses, check the
2664  * float bonuses now.
2665  */
2666  if (i == NUM_INT_BONUSES) {
2667  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2668  if (!strncasecmp(cp, float_bonus_names[i], strlen(float_bonus_names[i]))) {
2669  error = load_table_float(&new_float_bonuses[i], fp, cp);
2670  break;
2671  }
2672  }
2673  /* This may not actually be a critical error */
2674  if (i == NUM_FLOAT_BONUSES) {
2675  LOG(llevError,"Unknown line in stat_bonus file: %s\n", buf);
2676  }
2677  }
2678  if (error) break;
2679  }
2680  fclose(fp);
2681 
2682  /* Make sure that we have load tables for all the bonuses.
2683  * This is critical on initial load, but on reloads, it enusres that
2684  * all the bonus data matches.
2685  */
2686  for (i=0; i<NUM_INT_BONUSES; i++) {
2687  if (!new_int_bonuses[i]) {
2688  LOG(llevError,"No bonus loaded for %s\n", int_bonus_names[i]);
2689  error=2;
2690  }
2691  }
2692 
2693  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2694  if (!new_float_bonuses[i]) {
2695  LOG(llevError,"No bonus loaded for %s\n", float_bonus_names[i]);
2696  error=2;
2697  }
2698  }
2699 
2700  /* If we got an error, we just free up the data we read in and return/exit.
2701  * if no error, we make the tables we just read in into the default
2702  * tables.
2703  */
2704  if (error) {
2705  if (error==1)
2706  LOG(llevError,"Got error reading stat_bonus: %s\n", buf);
2707 
2708  if (reload) {
2709  for (i=0; i<NUM_INT_BONUSES; i++)
2710  if (new_int_bonuses[i]) FREE_AND_CLEAR(new_int_bonuses[i]);
2711  for (i=0; i<NUM_FLOAT_BONUSES; i++)
2712  if (new_float_bonuses[i]) FREE_AND_CLEAR(new_float_bonuses[i]);
2713  settings.max_stat = oldmax;
2714  } else {
2715  exit(1);
2716  }
2717  } else {
2718  /* Everything check out - now copy the data into
2719  * the live arrays.
2720  */
2721  for (i=0; i<NUM_INT_BONUSES; i++) {
2722  free(int_bonuses[i]);
2723  int_bonuses[i] = new_int_bonuses[i];
2724  new_int_bonuses[i] = NULL;
2725  }
2726 
2727  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2728  free(float_bonuses[i]);
2729  float_bonuses[i] = new_float_bonuses[i];
2730  new_float_bonuses[i] = NULL;
2731  }
2732  }
2733 }
#define INT_THAC0_BONUS
Definition: living.c:66
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:316
static float get_con_bonus(int stat)
Definition: living.c:2384
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:219
int8_t Int
Definition: living.h:36
#define NUM_BODY_LOCATIONS
Definition: object.h:13
Definition: player.h:92
#define FLAG_SEE_IN_DARK
Definition: define.h:338
archetype * find_archetype(const char *name)
Definition: arch.c:696
#define WEAPON_SPEED(xyz)
Definition: define.h:484
int8_t ac
Definition: living.h:38
#define MOVE_WALK
Definition: define.h:407
int64_t check_exp_adjust(const object *op, int64_t exp)
Definition: living.c:2085
MoveType move_type
Definition: object.h:426
#define FLOAT_CON_BONUS
Definition: living.c:86
void drain_stat(object *op)
Definition: living.c:713
int16_t gen_hp
Definition: player.h:113
Definition: object.h:185
object * find_applied_skill_by_name(const object *op, const char *name)
Definition: living.c:1915
uint8_t max_stat
Definition: global.h:326
int64_t level_exp(int level, double expmul)
Definition: living.c:1868
const char * race
Definition: object.h:318
const char *const restore_msg[NUM_STATS]
Definition: living.c:151
uint8_t spell_encumbrance
Definition: global.h:269
#define SET_FLAG(xyz, p)
Definition: define.h:223
sstring add_refcount(sstring str)
Definition: shstr.c:210
#define FABS(x)
Definition: define.h:22
uint32_t braced
Definition: player.h:124
static float get_grace_bonus(int stat)
Definition: living.c:2392
void link_player_skills(object *op)
Definition: player.c:279
int get_dam_bonus(int stat)
Definition: living.c:2372
#define INT_TURN_BONUS
Definition: living.c:60
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_LOSS
Definition: newclient.h:533
uint8_t death_penalty_level
Definition: global.h:261
#define FLAG_USE_ARMOUR
Definition: define.h:296
Definition: object.h:204
#define ADD_EXP(exptotal, exp)
Definition: living.c:42
Definition: living.h:14
int exp_level(int64_t exp)
Definition: living.c:1880
int16_t gen_grace
Definition: player.h:116
#define PERM_EXP_MAX_LOSS_RATIO
Definition: config.h:289
int16_t max_level
Definition: global.h:304
int16_t maxgrace
Definition: living.h:45
void free_string(sstring str)
Definition: shstr.c:280
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4135
#define NDI_BLUE
Definition: newclient.h:226
int8_t levsp[11]
Definition: player.h:168
object clone
Definition: object.h:472
int16_t invisible
Definition: object.h:361
Definition: living.h:17
Definition: object.h:119
Definition: object.h:136
const char * slaying
Definition: object.h:319
#define FLAG_CONFUSED
Definition: define.h:312
#define FLOAT_DEX_BONUS
Definition: living.c:87
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_GAIN
Definition: newclient.h:532
#define FLAG_STEALTH
Definition: define.h:313
int object_check_move_on(object *op, object *originator)
Definition: object.c:2743
object * ranges[range_size]
Definition: player.h:103
Definition: object.h:109
int64_t exp
Definition: living.h:47
void change_luck(object *op, int value)
Definition: living.c:793
double expmul
Definition: object.h:397
#define TRUE
Definition: compat.h:10
Definition: object.h:223
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.c:2953
Definition: living.h:35
int64_t check_exp_loss(const object *op, int64_t exp)
Definition: living.c:2060
Definition: object.h:139
int8_t get_attr_value(const living *stats, int attr)
Definition: living.c:314
uint32_t path_attuned
Definition: object.h:344
#define MAX(x, y)
Definition: compat.h:20
uint8_t death_penalty_ratio
Definition: global.h:260
int16_t sp
Definition: living.h:42
uint32_t get_weight_limit(int stat)
Definition: living.c:2356
#define MAX_EXPERIENCE
Definition: living.c:100
uint32_t path_repelled
Definition: object.h:345
Definition: object.h:212
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:311
const char *const drain_msg[NUM_STATS]
Definition: living.c:140
Definition: object.h:467
Definition: object.h:220
int16_t maxsp
Definition: living.h:43
#define MIN(x, y)
Definition: compat.h:17
int8_t Con
Definition: living.h:36
#define ADD_TOTALEXP(exptotal, exp)
Definition: living.c:43
#define FLAG_REMOVED
Definition: define.h:232
int16_t hp
Definition: living.h:40
partylist * party
Definition: player.h:186
#define IS_MANA_SKILL(num)
Definition: skills.h:106
object * give_skill_by_name(object *op, const char *skill_name)
Definition: living.c:1773
#define MIN_STAT
Definition: define.h:33
int64_t total_exp
Definition: object.h:371
#define FREE_PLAYER_LOAD_PERCENT
Definition: config.h:98
#define FLAG_UNDEAD
Definition: define.h:270
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:894
int get_cha_bonus(int stat)
Definition: living.c:2344
struct obj * chosen_skill
Definition: object.h:388
void object_free_drop_inventory(object *ob)
Definition: object.c:1325
int change_abil(object *op, object *tmp)
Definition: living.c:395
#define NDI_RED
Definition: newclient.h:224
int16_t maxhp
Definition: living.h:41
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
Definition: newclient.h:561
living applied_stats
Definition: player.h:152
#define NUM_FLOAT_BONUSES
Definition: living.c:90
void player_lvl_adj(object *who, object *op)
Definition: living.c:1813
Definition: object.h:118
uint32_t path_denied
Definition: object.h:346
#define MSG_TYPE_ATTRIBUTE_MOVE
Definition: newclient.h:554
#define FLAG_ALIVE
Definition: define.h:230
#define FLAG_REFL_SPELL
Definition: define.h:275
const char *const gain_msg[NUM_STATS]
Definition: living.c:162
static const int savethrow[MAX_SAVE_LEVEL+1]
Definition: living.c:114
int get_turn_bonus(int stat)
Definition: living.c:2368
static int load_table_int(int **bonuses, FILE *fp, char *bonus_name)
Definition: living.c:2432
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2601
#define SK_EXP_TOTAL
Definition: skills.h:79
int16_t gen_sp
Definition: player.h:114
#define MOVE_SWIM
Definition: define.h:411
#define MSG_TYPE_ATTRIBUTE_PROTECTION_GAIN
Definition: newclient.h:542
uint8_t search_items
Definition: global.h:268
static void subtract_player_exp(object *op, int64_t exp, const char *skill, int flag)
Definition: living.c:2114
#define FLAG_CAN_USE_SKILL
Definition: define.h:322
#define MOVE_FLY_LOW
Definition: define.h:408
const char *const statname[NUM_STATS]
Definition: living.c:184
int8_t Wis
Definition: living.h:36
int is_dragon_pl(const object *op)
Definition: player.c:114
char search_str[MAX_BUF]
Definition: player.h:192
#define snprintf
Definition: win32.h:46
#define ARCH_DEPLETION
Definition: object.h:579
void drain_specific_stat(object *op, int deplete_stats)
Definition: living.c:725
#define MSG_TYPE_ATTRIBUTE
Definition: newclient.h:380
#define PERM_EXP(exptotal)
Definition: global.h:234
#define FOR_INV_FINISH()
Definition: define.h:715
int16_t dam
Definition: living.h:46
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:122
void change_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:265
#define FLAG_PROBE
Definition: define.h:257
int32_t carrying
Definition: object.h:368
archetype * get_archetype_by_skill_name(const char *skill, int type)
Definition: arch.c:108
int get_fear_bonus(int stat)
Definition: living.c:2380
const char * name
Definition: object.h:311
living orig_stats
Definition: player.h:148
#define ARMOUR_SPEED(xyz)
Definition: define.h:482
int allowed_class(const object *op)
Definition: living.c:1646
#define INT_WEIGHT_LIMIT
Definition: living.c:67
static float get_sp_bonus(int stat)
Definition: living.c:2388
struct obj * current_weapon
Definition: object.h:372
#define MAX_PLAYER_SPEED
Definition: config.h:97
int8_t Cha
Definition: living.h:36
EXTERN const char *const change_resist_msg[NROFATTACKS]
Definition: attack.h:135
Definition: object.h:111
struct pl * contr
Definition: object.h:276
int8_t item_power
Definition: object.h:363
void add_statbonus(object *op)
Definition: living.c:865
#define MIN_PLAYER_SPEED
Definition: config.h:96
#define FLAG_XRAYS
Definition: define.h:301
#define INT_DAM_BONUS
Definition: living.c:65
#define MSG_TYPE_ATTRIBUTE_LEVEL_GAIN
Definition: newclient.h:564
static const char * float_bonus_names[NUM_FLOAT_BONUSES]
Definition: living.c:92
#define ATNR_PHYSICAL
Definition: attack.h:49
static void dragon_level_gain(object *who)
Definition: living.c:1713
static float * float_bonuses[NUM_FLOAT_BONUSES]
Definition: living.c:91
int8_t luck
Definition: living.h:39
#define AT_PHYSICAL
Definition: attack.h:76
float speed
Definition: object.h:328
int on_same_map(const object *op1, const object *op2)
Definition: map.c:2658
#define NUM_INT_BONUSES
Definition: living.c:68
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define BASE_WEAPON_SPEED
Definition: config.h:108
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define INT_LEARN_SPELL
Definition: living.c:62
static int * int_bonuses[NUM_INT_BONUSES]
Definition: living.c:70
#define FLAG_WIZ
Definition: define.h:231
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.c:2162
#define INT_FEAR_BONUS
Definition: living.c:59
#define MAX_BUF
Definition: define.h:35
#define FLOAT_SP_BONUS
Definition: living.c:88
int strncasecmp(const char *s1, const char *s2, int n)
Definition: porting.c:224
int16_t encumbrance
Definition: player.h:179
int8_t levhp[11]
Definition: player.h:167
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:563
const char * skill
Definition: object.h:321
int32_t last_eat
Definition: object.h:357
int8_t wc
Definition: living.h:37
const char * confdir
Definition: global.h:246
signed __int64 int64_t
Definition: win32.h:168
#define FLAG_READY_WEAPON
Definition: define.h:335
#define DIFF_MSG(flag, subtype1, subtype2, msg1, msg2)
Definition: living.c:370
int8_t Str
Definition: living.h:36
void calc_perm_exp(object *op)
Definition: living.c:1897
int16_t resist[NROFATTACKS]
Definition: object.h:342
object * ob
Definition: player.h:158
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START
Definition: newclient.h:566
const char *const lose_msg[NUM_STATS]
Definition: living.c:173
uint8_t permanent_exp_ratio
Definition: global.h:259
#define INT_DEX_BONUS
Definition: living.c:64
unsigned int uint32_t
Definition: win32.h:162
Definition: object.h:107
static void add_player_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.c:1954
Definition: object.h:135
#define INT_CLERIC_CHANCE
Definition: living.c:61
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:374
#define PREFER_HIGH
Definition: define.h:601
uint32_t attacktype
Definition: object.h:343
int64_t * levels
Definition: exp.c:26
#define FLAG_BLIND
Definition: define.h:337
#define RANDOM()
Definition: define.h:682
int16_t grace
Definition: living.h:44
signed char int8_t
Definition: win32.h:158
Definition: object.h:143
#define INT_CHA_BONUS
Definition: living.c:63
void player_set_dragon_title(struct pl *pl, int level, const char *attack, int skin_resist)
Definition: player.c:194
living stats
Definition: object.h:369
#define MSG_TYPE_ATTRIBUTE_STAT_GAIN
Definition: newclient.h:562
int8_t Dex
Definition: living.h:36
struct archt * arch
Definition: object.h:414
#define MSG_TYPE_ATTRIBUTE_LEVEL_LOSS
Definition: newclient.h:565
void init_stats(int reload)
Definition: living.c:2588
static size_t get_index(int stat, size_t max_index)
Definition: living.c:2404
uint8_t type
Definition: object.h:339
uint32_t do_los
Definition: player.h:126
struct Settings settings
Definition: init.c:39
static int load_table_float(float **bonuses, FILE *fp, char *bonus_name)
Definition: living.c:2508
int remove_depletion(object *op, int level)
Definition: living.c:752
#define SK_EXP_ADD_SKILL
Definition: skills.h:78
#define SK_EXP_NONE
Definition: skills.h:80
#define FLAG_APPLIED
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
#define FLAG_LIFESAVE
Definition: define.h:306
#define FLAG_MAKE_INVIS
Definition: define.h:329
void apply_death_exp_penalty(object *op)
Definition: living.c:2227
int16_t gen_sp_armour
Definition: player.h:115
#define MAX_SAVE_LEVEL
Definition: living.c:104
sstring add_string(const char *str)
Definition: shstr.c:124
EXTERN player * first_player
Definition: global.h:115
struct pl * next
Definition: player.h:93
#define MIN_ACTIVE_SPEED
Definition: define.h:677
int8_t glow_radius
Definition: object.h:365
#define FLAG_MONSTER
Definition: define.h:245
int8_t Pow
Definition: living.h:36
#define NDI_UNIQUE
Definition: newclient.h:245
int get_cleric_chance(int stat)
Definition: living.c:2364
Definition: object.h:213
#define MOVE_FLY_HIGH
Definition: define.h:409
void dragon_ability_gain(object *who, int atnr, int level)
Definition: main.c:346
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
int16_t item_power
Definition: player.h:117
int get_learn_spell(int stat)
Definition: living.c:2360
object * last_skill_ob[MAX_SKILLS]
Definition: player.h:137
int did_make_save(const object *op, int level, int bonus)
Definition: living.c:2276
#define MSG_TYPE_ATTRIBUTE_RACE
Definition: newclient.h:557
void set_dragon_name(object *pl, const object *abil, const object *skin)
Definition: living.c:1673
#define MSG_TYPE_ATTRIBUTE_PROTECTION_LOSS
Definition: newclient.h:543
#define MAX_SKILLS
Definition: skills.h:70
#define SK_SUBTRACT_SKILL_EXP
Definition: skills.h:81
void share_exp(object *op, int64_t exp, const char *skill, int flag)
Definition: living.c:2306
void remove_statbonus(object *op)
Definition: living.c:842
void esrv_update_spells(player *pl)
Definition: main.c:359
#define IS_COMBAT_SKILL(num)
Definition: skills.h:91
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
#define AT_CONFUSION
Definition: attack.h:81
#define FREE_AND_CLEAR(xyz)
Definition: global.h:200
int8_t levgrace[11]
Definition: player.h:169
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Definition: object.c:4066
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
Definition: newclient.h:569
Definition: object.h:120
const char *const short_stat_name[NUM_STATS]
Definition: living.c:195
#define FLAG_REFL_MISSILE
Definition: define.h:273
int get_dex_bonus(int stat)
Definition: living.c:2348
int16_t level
Definition: object.h:352
#define FLOAT_GRACE_BONUS
Definition: living.c:89
void fix_object(object *op)
Definition: living.c:1120
float weapon_speed
Definition: object.h:330
#define IS_GRACE_SKILL(num)
Definition: skills.h:120
float get_speed_bonus(int stat)
Definition: living.c:2376
static const char * int_bonus_names[NUM_INT_BONUSES]
Definition: living.c:76
object * arch_to_object(archetype *at)
Definition: arch.c:572
void object_update_speed(object *op)
Definition: object.c:1095
int16_t digestion
Definition: player.h:112
const char * name
Definition: object.h:468
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:708
void object_remove(object *op)
Definition: object.c:1587
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
Definition: newclient.h:558
const char *const attacks[NROFATTACKS]
Definition: living.c:130
int8_t body_used[NUM_BODY_LOCATIONS]
Definition: object.h:375
int atnr_is_dragon_enabled(int attacknr)
Definition: player.c:95
int32_t food
Definition: living.h:48
Definition: object.h:224
int get_thaco_bonus(int stat)
Definition: living.c:2352
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Definition: living.c:355