Crossfire Server, Trunk  R20513
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) { exptotal += exp; if (exptotal > MAX_EXPERIENCE) exptotal = MAX_EXPERIENCE; }
43 
58 #define INT_FEAR_BONUS 0
59 #define INT_TURN_BONUS 1
60 #define INT_CLERIC_CHANCE 2
61 #define INT_LEARN_SPELL 3
62 #define INT_CHA_BONUS 4
63 #define INT_DEX_BONUS 5
64 #define INT_DAM_BONUS 6
65 #define INT_THAC0_BONUS 7
66 #define INT_WEIGHT_LIMIT 8
67 #define NUM_INT_BONUSES 9
68 
70 
75 static const char *int_bonus_names[NUM_INT_BONUSES] = {
76  "cha_fear_bonus", "wis_turn_bonus", "wis_cleric_chance", "int_wis_learn_spell",
77  "cha_shop_bonus", "dex_bonus", "str_damage_bonus", "str_hit_bonus",
78  "str_weight_limit",
79 };
80 
85 #define FLOAT_CON_BONUS 0
86 #define FLOAT_DEX_BONUS 1
87 #define FLOAT_SP_BONUS 2
88 #define FLOAT_GRACE_BONUS 3
89 #define NUM_FLOAT_BONUSES 4
91 static const char *float_bonus_names[NUM_FLOAT_BONUSES] = {
92  "con_hp_bonus", "dex_speed_bonus", "pow_int_sp_bonus", "wis_pow_grace_bonus"
93 };
94 
95 /*
96  * Since this is nowhere defined ...
97  * Both come in handy at least in function add_exp()
98  */
99 #define MAX_EXPERIENCE levels[settings.max_level]
100 
101 extern int64_t *levels;
102 
103 #define MAX_SAVE_LEVEL 110
104 
113 static const int savethrow[MAX_SAVE_LEVEL+1] = {
114  18,
115  18, 17, 16, 15, 14, 14, 13, 13, 12, 12,
116  12, 11, 11, 11, 11, 10, 10, 10, 10, 9,
117  9, 9, 9, 9, 8, 8, 8, 8, 8, 8,
118  7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
119  6, 6, 6, 6, 6, 5, 5, 5, 5, 5,
120  5, 5, 5, 5, 4, 4, 4, 4, 4, 4,
121  4, 4, 4, 4, 3, 3, 3, 3, 3, 3,
122  3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
123  2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
124  1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
125  1, 1, 1, 1, 1, 1, 1, 1, 1, 1
126 };
127 
129 const char *const attacks[NROFATTACKS] = {
130  "physical", "magical", "fire", "electricity", "cold",
131  "confusion", "acid", "drain", "weaponmagic", "ghosthit",
132  "poison", "slow", "paralyze", "turn undead", "fear",
133  "cancellation", "depletion", "death", "chaos", "counterspell",
134  "god power", "holy power", "blinding", "", "life stealing",
135  "disease"
136 };
137 
139 static const char *const drain_msg[NUM_STATS] = {
140  "Oh no! You are weakened!",
141  "You're feeling clumsy!",
142  "Your health deteriorates!",
143  "You suddenly begin to lose your memory!",
144  "Your face gets distorted!",
145  "Watch out, your mind is going!",
146  "Your spirit feels drained!"
147 };
148 
150 const char *const restore_msg[NUM_STATS] = {
151  "You feel your strength return.",
152  "You feel your agility return.",
153  "You feel your health return.",
154  "You feel your wisdom return.",
155  "You feel your charisma return.",
156  "You feel your memory return.",
157  "You feel your spirits return."
158 };
159 
161 const char *const gain_msg[NUM_STATS] = {
162  "You feel stronger.",
163  "You feel more agile.",
164  "You feel healthy.",
165  "You feel wiser.",
166  "You seem to look better.",
167  "You feel smarter.",
168  "You feel more potent."
169 };
170 
172 const char *const lose_msg[NUM_STATS] = {
173  "You feel weaker!",
174  "You feel clumsy!",
175  "You feel less healthy!",
176  "You lose some of your memory!",
177  "You look ugly!",
178  "You feel stupid!",
179  "You feel less potent!"
180 };
181 
183 const char *const statname[NUM_STATS] = {
184  "strength",
185  "dexterity",
186  "constitution",
187  "wisdom",
188  "charisma",
189  "intelligence",
190  "power"
191 };
192 
194 const char *const short_stat_name[NUM_STATS] = {
195  "Str",
196  "Dex",
197  "Con",
198  "Wis",
199  "Cha",
200  "Int",
201  "Pow"
202 };
203 
218 void set_attr_value(living *stats, int attr, int8_t value) {
219  switch (attr) {
220  case STRENGTH:
221  stats->Str = value;
222  break;
223 
224  case DEXTERITY:
225  stats->Dex = value;
226  break;
227 
228  case CONSTITUTION:
229  stats->Con = value;
230  break;
231 
232  case WISDOM:
233  stats->Wis = value;
234  break;
235 
236  case POWER:
237  stats->Pow = value;
238  break;
239 
240  case CHARISMA:
241  stats->Cha = value;
242  break;
243 
244  case INTELLIGENCE:
245  stats->Int = value;
246  break;
247  }
248 }
249 
264 void change_attr_value(living *stats, int attr, int8_t value) {
265  if (value == 0)
266  return;
267  switch (attr) {
268  case STRENGTH:
269  stats->Str += value;
270  break;
271 
272  case DEXTERITY:
273  stats->Dex += value;
274  break;
275 
276  case CONSTITUTION:
277  stats->Con += value;
278  break;
279 
280  case WISDOM:
281  stats->Wis += value;
282  break;
283 
284  case POWER:
285  stats->Pow += value;
286  break;
287 
288  case CHARISMA:
289  stats->Cha += value;
290  break;
291 
292  case INTELLIGENCE:
293  stats->Int += value;
294  break;
295 
296  default:
297  LOG(llevError, "Invalid attribute in change_attr_value: %d\n", attr);
298  }
299 }
300 
313 int8_t get_attr_value(const living *stats, int attr) {
314  switch (attr) {
315  case STRENGTH:
316  return(stats->Str);
317 
318  case DEXTERITY:
319  return(stats->Dex);
320 
321  case CONSTITUTION:
322  return(stats->Con);
323 
324  case WISDOM:
325  return(stats->Wis);
326 
327  case CHARISMA:
328  return(stats->Cha);
329 
330  case INTELLIGENCE:
331  return(stats->Int);
332 
333  case POWER:
334  return(stats->Pow);
335  }
336  return 0;
337 }
338 
354 void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat) {
355  int i, v;
356  for (i = 0; i < NUM_STATS; i++)
357  if ((v = get_attr_value(stats, i)) > max_stat)
358  set_attr_value(stats, i, max_stat);
359  else if (v < min_stat)
360  set_attr_value(stats, i, min_stat);
361 }
362 
363 
369 #define DIFF_MSG(flag, subtype1, subtype2, msg1, msg2) \
370  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, (flag > 0) ? subtype1 : subtype2, (flag > 0) ? msg1 : msg2);
371 
394 int change_abil(object *op, object *tmp) {
395  int flag = QUERY_FLAG(tmp, FLAG_APPLIED) ? 1 : -1, i, j, success = 0;
396  object refop;
397  int potion_max = 0;
398 
399  /* remember what object was like before it was changed. note that
400  * refop is a local copy of op only to be used for detecting changes
401  * found by fix_object. refop is not a real object
402  */
403  memcpy(&refop, op, sizeof(object));
404 
405  if (op->type == PLAYER) {
406  if (tmp->type == POTION) {
407  potion_max = 1;
408  for (j = 0; j < NUM_STATS; j++) {
409  int nstat, ostat;
410 
411  ostat = get_attr_value(&(op->contr->orig_stats), j);
412  i = get_attr_value(&(tmp->stats), j);
413 
414  /* nstat is what the stat will be after use of the potion */
415  nstat = flag*i+ostat;
416 
417  /* Do some bounds checking. While I don't think any
418  * potions do so right now, there is the potential for potions
419  * that adjust that stat by more than one point, so we need
420  * to allow for that.
421  */
422  if (nstat < 1 && i*flag < 0)
423  nstat = 1;
424  else if (nstat > 20+get_attr_value(&(op->arch->clone.stats), j)) {
425  nstat = 20+get_attr_value(&(op->arch->clone.stats), j);
426  }
427  if (nstat != ostat) {
428  set_attr_value(&(op->contr->orig_stats), j, nstat);
429  potion_max = 0;
430  } else if (i) {
431  /* potion is useless - player has already hit the natural maximum */
432  potion_max = 1;
433  }
434  }
435  /* This section of code ups the characters normal stats also. I am not
436  * sure if this is strictly necessary, being that fix_object probably
437  * recalculates this anyway.
438  */
439  for (j = 0; j < NUM_STATS; j++)
440  change_attr_value(&(op->stats), j, flag*get_attr_value(&(tmp->stats), j));
442  } /* end of potion handling code */
443  }
444 
445  /* reset attributes that fix_object doesn't reset since it doesn't search
446  * everything to set
447  */
448  if (flag == -1) {
449  op->attacktype &= ~tmp->attacktype;
450  op->path_attuned &= ~tmp->path_attuned;
451  op->path_repelled &= ~tmp->path_repelled;
452  op->path_denied &= ~tmp->path_denied;
453  /* Presuming here that creatures only have move_type,
454  * and not the other move_ fields.
455  */
456  op->move_type &= ~tmp->move_type;
457  }
458 
459  /* call fix_object since op object could have whatever attribute due
460  * to multiple items. if fix_object always has to be called after
461  * change_ability then might as well call it from here
462  */
463  fix_object(op);
464 
465  /* Fix player won't add the bows ability to the player, so don't
466  * print out message if this is a bow.
467  */
468  if (tmp->attacktype&AT_CONFUSION && tmp->type != BOW) {
469  success = 1;
471  "Your hands begin to glow red.",
472  "Your hands stop glowing red.");
473  }
474  if (QUERY_FLAG(op, FLAG_LIFESAVE) != QUERY_FLAG(&refop, FLAG_LIFESAVE)) {
475  success = 1;
477  "You feel very protected.",
478  "You don't feel protected anymore.");
479  }
481  success = 1;
483  "A magic force shimmers around you.",
484  "The magic force fades away.");
485  }
486  if (QUERY_FLAG(op, FLAG_REFL_SPELL) != QUERY_FLAG(&refop, FLAG_REFL_SPELL)) {
487  success = 1;
489  "You feel more safe now, somehow.",
490  "Suddenly you feel less safe, somehow.");
491  }
492  /* movement type has changed. We don't care about cases where
493  * user has multiple items giving the same type appled like we
494  * used to - that is more work than what we gain, plus messages
495  * can be misleading (a little higher could be miscontrued from
496  * from fly high)
497  */
498  if (tmp->move_type && op->move_type != refop.move_type) {
499  success = 1;
500 
501  /* MOVE_FLY_HIGH trumps MOVE_FLY_LOW - changing your move_fly_low
502  * status doesn't make a difference if you are flying high
503  */
504  if (tmp->move_type&MOVE_FLY_LOW && !(op->move_type&MOVE_FLY_HIGH)) {
506  "You start to float in the air!",
507  "You float down to the ground.");
508  }
509 
510  if (tmp->move_type&MOVE_FLY_HIGH) {
511  /* double conditional - second case covers if you have move_fly_low -
512  * in that case, you don't actually land
513  */
515  "You soar into the air!.",
516  (op->move_type&MOVE_FLY_LOW ? "You glide closer to the ground.":
517  "You float down to the ground."));
518  }
519  if (tmp->move_type&MOVE_SWIM)
521  "You feel ready for a swim",
522  "You no longer feel like swimming");
523 
524  /* Changing move status may mean you are affected by things you weren't before */
525  object_check_move_on(op, op);
526  }
527 
528  /* becoming UNDEAD... a special treatment for this flag. Only those not
529  * originally undead may change their status
530  */
531  if (!QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
532  if (QUERY_FLAG(op, FLAG_UNDEAD) != QUERY_FLAG(&refop, FLAG_UNDEAD)) {
533  success = 1;
534  if (flag > 0) {
535  if (op->race)
536  free_string(op->race);
537  op->race = add_string("undead");
538  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_RACE, "Your lifeforce drains away!");
539  } else {
540  if (op->race)
541  free_string(op->race);
542  if (op->arch->clone.race)
543  op->race = add_string(op->arch->clone.race);
544  else
545  op->race = NULL;
546  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_RACE, "Your lifeforce returns!");
547  }
548  }
549 
550  if (QUERY_FLAG(op, FLAG_STEALTH) != QUERY_FLAG(&refop, FLAG_STEALTH)) {
551  success = 1;
553  "You walk more quietly.",
554  "You walk more noisily.");
555  }
556  if (QUERY_FLAG(op, FLAG_MAKE_INVIS) != QUERY_FLAG(&refop, FLAG_MAKE_INVIS)) {
557  success = 1;
559  "You become transparent.",
560  "You can see yourself.");
561  }
562  /* blinded you can tell if more blinded since blinded player has minimal
563  * vision
564  */
565  if (QUERY_FLAG(tmp, FLAG_BLIND)) {
566  success = 1;
567  if (flag > 0) {
568  if (QUERY_FLAG(op, FLAG_WIZ))
569  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START, "Your mortal self is blinded.");
570  else {
572  SET_FLAG(op, FLAG_BLIND);
573  if (op->type == PLAYER)
574  op->contr->do_los = 1;
575  }
576  } else {
577  if (QUERY_FLAG(op, FLAG_WIZ))
578  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END, "Your mortal self can now see again.");
579  else {
581  CLEAR_FLAG(op, FLAG_BLIND);
582  if (op->type == PLAYER)
583  op->contr->do_los = 1;
584  }
585  }
586  }
587 
589  success = 1;
590  if (op->type == PLAYER)
591  op->contr->do_los = 1;
593  "Your vision is better in the dark.",
594  "You see less well in the dark.");
595  }
596 
597  if (QUERY_FLAG(op, FLAG_XRAYS) != QUERY_FLAG(&refop, FLAG_XRAYS)) {
598  success = 1;
599  if (flag > 0) {
600  if (QUERY_FLAG(op, FLAG_WIZ))
601  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START, "Your vision becomes a little clearer.");
602  else {
603  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START, "Everything becomes transparent.");
604  if (op->type == PLAYER)
605  op->contr->do_los = 1;
606  }
607  } else {
608  if (QUERY_FLAG(op, FLAG_WIZ))
609  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END, "Your vision becomes a bit out of focus.");
610  else {
611  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END, "Everything suddenly looks very solid.");
612  if (op->type == PLAYER)
613  op->contr->do_los = 1;
614  }
615  }
616  }
617 
618  if (tmp->stats.luck) {
619  success = 1;
621  "You feel more lucky.",
622  "You feel less lucky.");
623  }
624 
625  if (tmp->stats.hp && op->type == PLAYER) {
626  success = 1;
628  "You feel much more healthy!",
629  "You feel much less healthy!");
630  }
631 
632  if (tmp->stats.sp && op->type == PLAYER && tmp->type != SKILL) {
633  success = 1;
635  "You feel one with the powers of magic!",
636  "You suddenly feel very mundane.");
637  }
638 
639  /* for the future when artifacts set this -b.t. */
640  if (tmp->stats.grace && op->type == PLAYER) {
641  success = 1;
643  "You feel closer to your god!",
644  "You suddenly feel less holy.");
645  }
646 
647  if (tmp->stats.wc && op->type == PLAYER) {
648  success = 1;
650  "You feel more confident in combat.",
651  "You feel less confident in combat.");
652  }
653 
654  if (tmp->stats.ac && op->type == PLAYER) {
655  success = 1;
657  "You feel more confident in your dodging skills.",
658  "You feel less confident in your dodging skills.");
659  }
660 
661  if (tmp->stats.exp && tmp->type != SKILL && op->type == PLAYER) {
662  success = 1;
664  "You feel like you're moving faster.",
665  "You feel like you're moving more slowly.");
666  }
667 
668  if (tmp->stats.food && op->type == PLAYER) {
669  success = 1;
671  "You feel your digestion slowing down.",
672  "You feel your digestion speeding up.");
673  }
674 
675  /* Messages for changed resistance */
676  for (i = 0; i < NROFATTACKS; i++) {
677  if (i == ATNR_PHYSICAL)
678  continue; /* Don't display about armour */
679 
680  if (op->resist[i] != refop.resist[i]) {
681  success = 1;
682  if (op->resist[i] > refop.resist[i])
684  "Your resistance to %s rises to %d%%.",
685  change_resist_msg[i], op->resist[i]);
686  else
688  "Your resistance to %s drops to %d%%.",
689  change_resist_msg[i], op->resist[i]);
690  }
691  }
692 
693  if (!potion_max) {
694  for (j = 0; j < NUM_STATS; j++) {
695  if ((i = get_attr_value(&(tmp->stats), j)) != 0) {
696  success = 1;
698  }
699  }
700  }
701  return success;
702 }
703 
712 void drain_stat(object *op) {
714 }
715 
724 void drain_specific_stat(object *op, int deplete_stats) {
725  object *tmp;
726  archetype *at;
727 
729  if (!at) {
730  return;
731  } else {
732  tmp = arch_present_in_ob(at, op);
733  if (!tmp) {
734  tmp = arch_to_object(at);
735  tmp = object_insert_in_ob(tmp, op);
736  SET_FLAG(tmp, FLAG_APPLIED);
737  }
738  }
739 
741  change_attr_value(&tmp->stats, deplete_stats, -1);
742  fix_object(op);
743 }
744 
751 int remove_depletion(object *op, int level) {
752  object *depl;
753  archetype *at;
754  int i, count = 0;
755 
756  if ((at = find_archetype(ARCH_DEPLETION)) == NULL) {
757  return 0;
758  }
759 
760  depl = arch_present_in_ob(at, op);
761 
762  if (depl == NULL)
763  return 0;
764 
765  if (level != -1 && level < op->level)
766  return 0;
767 
768  for (i = 0; i < NUM_STATS; i++) {
769  if (get_attr_value(&depl->stats, i)) {
770  count++;
772  }
773  }
774 
775  object_remove(depl);
777  fix_object(op);
778 
779  return (count == 0) ? 0 : 1;
780 }
781 
791 void change_luck(object *op, int value) {
792  object *tmp;
793  archetype *at;
794  int new_luck;
795 
796  at = find_archetype("luck");
797  if (!at)
798  ;
799  else {
800  tmp = arch_present_in_ob(at, op);
801  if (!tmp) {
802  if (!value)
803  return;
804  tmp = arch_to_object(at);
805  tmp = object_insert_in_ob(tmp, op);
806  SET_FLAG(tmp, FLAG_APPLIED);
807  }
808  if (value) {
809  /* Limit the luck value of the bad luck object to +/-100. This
810  * (arbitrary) value prevents overflows (both in the bad luck object and
811  * in op itself).
812  */
813  new_luck = tmp->stats.luck+value;
814  if (new_luck >= -100 && new_luck <= 100) {
815  op->stats.luck += value;
816  tmp->stats.luck = new_luck;
817  }
818  } else {
819  if (!tmp->stats.luck) {
820  return;
821  }
822  /* Randomly change the players luck. Basically, we move it
823  * back neutral (if greater>0, subtract, otherwise add)
824  */
825  if (RANDOM()%(FABS(tmp->stats.luck)) >= RANDOM()%30) {
826  int diff = tmp->stats.luck > 0 ? -1 : 1;
827  op->stats.luck += diff;
828  tmp->stats.luck += diff;
829  }
830  }
831  }
832 }
833 
840 void remove_statbonus(object *op) {
841  op->stats.Str -= op->arch->clone.stats.Str;
842  op->stats.Dex -= op->arch->clone.stats.Dex;
843  op->stats.Con -= op->arch->clone.stats.Con;
844  op->stats.Wis -= op->arch->clone.stats.Wis;
845  op->stats.Pow -= op->arch->clone.stats.Pow;
846  op->stats.Cha -= op->arch->clone.stats.Cha;
847  op->stats.Int -= op->arch->clone.stats.Int;
848  op->contr->orig_stats.Str -= op->arch->clone.stats.Str;
849  op->contr->orig_stats.Dex -= op->arch->clone.stats.Dex;
850  op->contr->orig_stats.Con -= op->arch->clone.stats.Con;
851  op->contr->orig_stats.Wis -= op->arch->clone.stats.Wis;
852  op->contr->orig_stats.Pow -= op->arch->clone.stats.Pow;
853  op->contr->orig_stats.Cha -= op->arch->clone.stats.Cha;
854  op->contr->orig_stats.Int -= op->arch->clone.stats.Int;
855 }
856 
863 void add_statbonus(object *op) {
864  op->stats.Str += op->arch->clone.stats.Str;
865  op->stats.Dex += op->arch->clone.stats.Dex;
866  op->stats.Con += op->arch->clone.stats.Con;
867  op->stats.Wis += op->arch->clone.stats.Wis;
868  op->stats.Pow += op->arch->clone.stats.Pow;
869  op->stats.Cha += op->arch->clone.stats.Cha;
870  op->stats.Int += op->arch->clone.stats.Int;
871  op->contr->orig_stats.Str += op->arch->clone.stats.Str;
872  op->contr->orig_stats.Dex += op->arch->clone.stats.Dex;
873  op->contr->orig_stats.Con += op->arch->clone.stats.Con;
874  op->contr->orig_stats.Wis += op->arch->clone.stats.Wis;
875  op->contr->orig_stats.Pow += op->arch->clone.stats.Pow;
876  op->contr->orig_stats.Cha += op->arch->clone.stats.Cha;
877  op->contr->orig_stats.Int += op->arch->clone.stats.Int;
878 }
879 
892 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)
893 {
894  int pl_level, i;
895  float character_load = 0.0, maxhp, tmpf;
896 
897  if (op->type != PLAYER)
898  return;
899 
901  pl_level = op->level;
902 
903  if (pl_level < 1)
904  pl_level = 1; /* safety, we should always get 1 levels worth of hp! */
905 
906  /*
907  * We store maxhp as a float to hold any fractional hp bonuses,
908  * (eg, 2.5 con bonus). While it may seem simpler to just
909  * do a get_con_bonus() * min(level,10), there is also a 1 hp/level
910  * minimum (including bonus), se we have to do the logic on a
911  * level basis.
912  */
913  maxhp = 0.0;
914  for (i = 1, op->stats.maxhp = 0; i <= pl_level && i <= 10; i++) {
915 
916  tmpf = op->contr->levhp[i]+get_con_bonus(op->stats.Con);
917 
918  /* always get at least 1 hp/level */
919  if (tmpf < 1.0) tmpf = 1.0;
920 
921  maxhp += tmpf;
922  }
923 
924  /* Add 0.5 so that this rounds normally - the cast just drops the
925  * fraction, so 1.5 becomes 1.
926  */
927  op->stats.maxhp = (int)(maxhp + 0.5);
928  if (op->level > 10)
929  op->stats.maxhp += 2 * (op->level - 10);
930 
931  op->stats.maxhp += op->arch->clone.stats.maxhp;
932 
933  if (op->stats.hp > op->stats.maxhp)
934  op->stats.hp = op->stats.maxhp;
935 
936  /* Sp gain is controlled by the level of the player's
937  * relevant experience object (mana_obj, see above) */
938 
939  /* set maxsp */
940  if (!mana_obj || !mana_obj->level) {
941  op->stats.maxsp = 1;
942  } else {
943  float sp_tmp = 0.0, mana_bonus;
944  int mana_lvl_max;
945 
946  mana_lvl_max = (mana_obj->level >10 ? 10: mana_obj->level);
947  mana_bonus = (2.0*get_sp_bonus(op->stats.Pow)+get_sp_bonus(op->stats.Int)) / 3.0;
948 
949  for (i = 1; i <= mana_lvl_max; i++) {
950  float stmp;
951 
952  stmp = op->contr->levsp[i] + mana_bonus;
953 
954  /* Got some extra bonus at first level */
955  if (i == 1) stmp += mana_bonus;
956 
957  if (stmp < 1.0)
958  stmp = 1.0;
959 
960  sp_tmp += stmp;
961  }
962 
963  op->stats.maxsp = (int)sp_tmp+op->arch->clone.stats.maxsp;
964 
965  if (mana_obj->level > 10)
966  op->stats.maxsp += 2 * (mana_obj->level - 10);
967  }
968 
969  /* Characters can get their sp supercharged via rune of transferrance */
970  if (op->stats.sp > op->stats.maxsp*2)
971  op->stats.sp = op->stats.maxsp*2;
972 
973  /* set maxgrace, notice 3-4 lines below it depends on both Wis and Pow */
974  if (!grace_obj || !grace_obj->level) {
975  op->stats.maxgrace = 1;
976  } else {
977  /* store grace in a float - this way, the divisions below don't create
978  * big jumps when you go from level to level - with int's, it then
979  * becomes big jumps when the sums of the bonuses jump to the next
980  * step of 8 - with floats, even fractional ones are useful.
981  */
982  float sp_tmp = 0.0, grace_bonus;
983 
984  grace_bonus = (get_grace_bonus(op->stats.Pow)+2.0*get_grace_bonus(op->stats.Wis)) / 3.0;
985 
986  for (i = 1; i <= grace_obj->level && i <= 10; i++) {
987  float grace_tmp = 0.0;
988 
989  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);
1168  if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_SPELL))
1170  if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_MISSILE))
1172  if (!QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
1173  CLEAR_FLAG(op, FLAG_UNDEAD);
1174  if (!QUERY_FLAG(&op->arch->clone, FLAG_SEE_IN_DARK))
1176  CLEAR_FLAG(op, FLAG_PROBE);
1177 
1178  op->path_attuned = op->arch->clone.path_attuned;
1180  op->path_denied = op->arch->clone.path_denied;
1181  op->glow_radius = op->arch->clone.glow_radius;
1182  op->move_type = op->arch->clone.move_type;
1183  op->chosen_skill = NULL;
1184 
1185  /* initializing resistances from the values in player/monster's
1186  * archetype clone
1187  */
1188  memcpy(&op->resist, &op->arch->clone.resist, sizeof(op->resist));
1189 
1190  for (i = 0; i < NROFATTACKS; i++) {
1191  if (op->resist[i] > 0)
1192  prot[i] = op->resist[i], vuln[i] = 0;
1193  else
1194  vuln[i] = -(op->resist[i]), prot[i] = 0;
1195  potion_resist[i] = 0;
1196  }
1197 
1198  wc = op->arch->clone.stats.wc;
1199  op->stats.dam = op->arch->clone.stats.dam;
1200 
1201  /* for players which cannot use armour, they gain AC -1 per 3 levels,
1202  * plus a small amount of physical resist, those poor suckers. ;)
1203  * the fact that maxlevel is factored in could be considered sort of bogus -
1204  * we should probably give them some bonus and cap it off - otherwise,
1205  * basically, if a server updates its max level, these playes may find
1206  * that their protection from physical goes down
1207  */
1208  if (!QUERY_FLAG(op, FLAG_USE_ARMOUR) && op->type == PLAYER) {
1209  ac = MAX(-10, op->arch->clone.stats.ac-op->level/3);
1210  prot[ATNR_PHYSICAL] += ((100-prot[AT_PHYSICAL])*(80*op->level/settings.max_level))/100;
1211  } else
1212  ac = op->arch->clone.stats.ac;
1213 
1214  op->stats.luck = op->arch->clone.stats.luck;
1215  op->speed = op->arch->clone.speed;
1216 
1217  /* OK - we've reset most all the objects attributes to sane values.
1218  * now go through and make adjustments for what the player has equipped.
1219  */
1220 
1221  FOR_INV_PREPARE(op, tmp) {
1222  /* See note in map.c:update_position about making this additive
1223  * since light sources are never applied, need to put check here.
1224  */
1225  if (tmp->glow_radius > op->glow_radius)
1226  op->glow_radius = tmp->glow_radius;
1227 
1228  /* This happens because apply_potion calls change_abil with the potion
1229  * applied so we can tell the player what chagned. But change_abil
1230  * then calls this function.
1231  */
1232  if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == POTION)
1233  continue;
1234 
1235  /* For some things, we don't care what is equipped */
1236  if (tmp->type == SKILL) {
1237  /* Want to take the highest skill here. */
1238  if (IS_MANA_SKILL(tmp->subtype)) {
1239  if (!mana_obj)
1240  mana_obj = tmp;
1241  else if (tmp->level > mana_obj->level)
1242  mana_obj = tmp;
1243  }
1244  if (IS_GRACE_SKILL(tmp->subtype)) {
1245  if (!grace_obj)
1246  grace_obj = tmp;
1247  else if (tmp->level > grace_obj->level)
1248  grace_obj = tmp;
1249  }
1250  }
1251 
1252  /* Container objects are not meant to adjust a players, but other applied
1253  * objects need to make adjustments.
1254  * This block should handle all player specific changes
1255  * The check for Praying is a bit of a hack - god given bonuses are put
1256  * in the praying skill, and the player should always get those.
1257  * It also means we need to put in additional checks for applied below,
1258  * because the skill shouldn't count against body positions being used
1259  * up, etc.
1260  */
1261  if ((QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type != CONTAINER && tmp->type != CLOSE_CON)
1262  || (tmp->type == SKILL && tmp->subtype == SK_PRAYING)) {
1263  if (op->type == PLAYER) {
1264  if (tmp->type == BOW)
1265  op->contr->ranges[range_bow] = tmp;
1266 
1267  if (tmp->type == WAND || tmp->type == ROD)
1268  op->contr->ranges[range_misc] = tmp;
1269 
1270  for (i = 0; i < NUM_STATS; i++) {
1271  int8_t value;
1272 
1273  value = get_attr_value(&(tmp->stats), i);
1274  change_attr_value(&(op->stats), i, value);
1275  if (strcmp(tmp->arch->clone.name, ARCH_DEPLETION) != 0)
1276  change_attr_value(&(op->contr->applied_stats), i, value);
1277  }
1278 
1279  /* For this temporary calculation, allow wider range of stat - if we have
1280  * having that gives +5 and different object that gives -5 and stat
1281  * is maxed, we don't want different results based on order of
1282  * inventory.
1283  */
1284  check_stat_bounds(&(tmp->stats), -settings.max_stat, 2*settings.max_stat);
1285 
1286  /* these are the items that currently can change digestion, regeneration,
1287  * spell point recovery and mana point recovery. Seems sort of an arbitary
1288  * list, but other items store other info into stats array.
1289  */
1290  switch (tmp->type)
1291  {
1292  case WEAPON:
1293  case ARMOUR:
1294  case HELMET:
1295  case SHIELD:
1296  case RING:
1297  case BOOTS:
1298  case GLOVES:
1299  case AMULET:
1300  case GIRDLE:
1301  case BRACERS:
1302  case CLOAK:
1303  case DISEASE:
1304  case FORCE:
1305  case SKILL:
1306  op->contr->digestion += tmp->stats.food;
1307  op->contr->gen_hp += tmp->stats.hp;
1308  op->contr->gen_sp += tmp->stats.sp;
1309  op->contr->gen_grace += tmp->stats.grace;
1310  op->contr->gen_sp_armour += tmp->gen_sp_armour;
1311  /*FALLTHROUGH*/
1312 
1313  /* Bow and skill utils need to update item_power specifically.
1314  * This should fix bug #648
1315  * Daniel Hawkins 2017-08-09
1316  */
1317  case BOW:
1318  case SKILL_TOOL:
1319  op->contr->item_power += tmp->item_power;
1320  break;
1321  }
1322  } /* if this is a player */
1323 
1324  /* Update slots used for items */
1325  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1326  for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1327  op->body_used[i] += tmp->body_info[i];
1328  }
1329 
1330  if (tmp->type == SYMPTOM && tmp->last_sp) {
1331  /* Should take the worst disease of the bunch */
1332  if (((float)tmp->last_sp/100.0) < speed_reduce_from_disease)
1333  speed_reduce_from_disease = (float)tmp->last_sp/100.0;
1334  }
1335 
1336  /* Pos. and neg. protections are counted seperate (-> pro/vuln).
1337  * (Negative protections are calculated extactly like positive.)
1338  * Resistance from potions are treated special as well. If there's
1339  * more than one potion-effect, the bigger prot.-value is taken.
1340  */
1341  if (tmp->type != POTION) {
1342  for (i = 0; i < NROFATTACKS; i++) {
1343  /* Potential for cursed potions, in which case we just can use
1344  * a straight MAX, as potion_resist is initialized to zero.
1345  */
1346  if (tmp->type == POTION_RESIST_EFFECT) {
1347  if (potion_resist[i])
1348  potion_resist[i] = MAX(potion_resist[i], tmp->resist[i]);
1349  else
1350  potion_resist[i] = tmp->resist[i];
1351  } else if (tmp->resist[i] > 0)
1352  prot[i] += ((100-prot[i])*tmp->resist[i])/100;
1353  else if (tmp->resist[i] < 0)
1354  vuln[i] += ((100-vuln[i])*(-tmp->resist[i]))/100;
1355  }
1356  }
1357 
1358  /* There may be other things that should not adjust the attacktype */
1359  if (tmp->type != BOW && tmp->type != SYMPTOM)
1360  op->attacktype |= tmp->attacktype;
1361 
1362  op->path_attuned |= tmp->path_attuned;
1363  op->path_repelled |= tmp->path_repelled;
1364  op->path_denied |= tmp->path_denied;
1365  op->stats.luck += tmp->stats.luck;
1366  op->move_type |= tmp->move_type;
1367 
1368  if (QUERY_FLAG(tmp, FLAG_LIFESAVE))
1369  SET_FLAG(op, FLAG_LIFESAVE);
1370  if (QUERY_FLAG(tmp, FLAG_REFL_SPELL))
1372  if (QUERY_FLAG(tmp, FLAG_REFL_MISSILE))
1374  if (QUERY_FLAG(tmp, FLAG_STEALTH))
1375  SET_FLAG(op, FLAG_STEALTH);
1376  if (QUERY_FLAG(tmp, FLAG_XRAYS))
1377  SET_FLAG(op, FLAG_XRAYS);
1378  if (QUERY_FLAG(tmp, FLAG_BLIND))
1379  SET_FLAG(op, FLAG_BLIND);
1380  if (QUERY_FLAG(tmp, FLAG_SEE_IN_DARK))
1382  if (QUERY_FLAG(tmp, FLAG_PROBE))
1383  SET_FLAG(op, FLAG_PROBE);
1384 
1385  if (QUERY_FLAG(tmp, FLAG_UNDEAD) && !QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
1386  SET_FLAG(op, FLAG_UNDEAD);
1387 
1388  if (QUERY_FLAG(tmp, FLAG_MAKE_INVIS)) {
1390  op->invisible = 1;
1391  }
1392 
1393  if (tmp->stats.exp && tmp->type != SKILL) {
1394  added_speed += (float)tmp->stats.exp/3.0;
1395  }
1396 
1397  switch (tmp->type) {
1398  /* skills modifying the character -b.t. */
1399  /* for all skills and skill granting objects */
1400  case SKILL:
1401  if (!QUERY_FLAG(tmp, FLAG_APPLIED))
1402  break;
1403 
1404  if (IS_COMBAT_SKILL(tmp->subtype))
1405  wc_obj = tmp;
1406 
1407  if (op->chosen_skill) {
1408  LOG(llevDebug, "fix_object, op %s has multiple skills applied\n", op->name);
1409  }
1410  op->chosen_skill = tmp;
1411  if (tmp->stats.dam > 0) { /* skill is a 'weapon' */
1412  if (!QUERY_FLAG(op, FLAG_READY_WEAPON))
1413  weapon_speed = (int)WEAPON_SPEED(tmp);
1414  if (weapon_speed < 0)
1415  weapon_speed = 0;
1416  op->stats.dam += tmp->stats.dam*(1+(op->chosen_skill->level/9));
1417  op->stats.dam += tmp->magic;
1418  }
1419  if (tmp->stats.wc)
1420  wc -= (tmp->stats.wc+tmp->magic);
1421 
1422  if (tmp->slaying != NULL) {
1423  if (op->slaying != NULL)
1424  free_string(op->slaying);
1425  add_refcount(op->slaying = tmp->slaying);
1426  }
1427 
1428  if (tmp->stats.ac)
1429  ac -= (tmp->stats.ac+tmp->magic);
1430  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1431  op->contr->encumbrance += (int)3*tmp->weight/1000;
1432  if (op->type == PLAYER)
1433  op->contr->ranges[range_skill] = op;
1434  break;
1435 
1436  case SKILL_TOOL:
1437  if (op->chosen_skill) {
1438  LOG(llevDebug, "fix_object, op %s has multiple skills applied\n", op->name);
1439  }
1440  op->chosen_skill = tmp;
1441  if (op->type == PLAYER)
1442  op->contr->ranges[range_skill] = op;
1443  break;
1444 
1445  case SHIELD:
1446  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1447  op->contr->encumbrance += (int)tmp->weight/2000;
1448  case RING:
1449  case AMULET:
1450  case GIRDLE:
1451  case HELMET:
1452  case BOOTS:
1453  case GLOVES:
1454  case CLOAK:
1455  if (tmp->stats.wc)
1456  wc -= tmp->stats.wc;
1457  if (tmp->stats.dam)
1458  op->stats.dam += (tmp->stats.dam+tmp->magic);
1459  if (tmp->stats.ac)
1460  ac -= (tmp->stats.ac+tmp->magic);
1461  break;
1462 
1463  case WEAPON:
1464  wc -= tmp->stats.wc;
1465  if (tmp->stats.ac && tmp->stats.ac+tmp->magic > 0)
1466  ac -= tmp->stats.ac+tmp->magic;
1467  op->stats.dam += (tmp->stats.dam+tmp->magic);
1468  weapon_speed = ((int)WEAPON_SPEED(tmp)*2-tmp->magic)/2;
1469  if (weapon_speed < 0)
1470  weapon_speed = 0;
1471  if (tmp->slaying != NULL) {
1472  if (op->slaying != NULL)
1473  free_string(op->slaying);
1474  add_refcount(op->slaying = tmp->slaying);
1475  }
1476  /* If there is desire that two handed weapons should do
1477  * extra strength damage, this is where the code should
1478  * go.
1479  */
1480  op->current_weapon = tmp;
1481  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1482  op->contr->encumbrance += (int)3*tmp->weight/1000;
1483  break;
1484 
1485  case ARMOUR: /* Only the best of these three are used: */
1486  if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1487  op->contr->encumbrance += (int)tmp->weight/1000;
1488 
1489  /* ARMOUR falls through to here */
1490 
1491  case BRACERS:
1492  case FORCE:
1493  if (tmp->stats.wc) {
1494  if (best_wc < tmp->stats.wc) {
1495  wc += best_wc;
1496  best_wc = tmp->stats.wc;
1497  } else
1498  wc += tmp->stats.wc;
1499  }
1500  if (tmp->stats.ac) {
1501  if (best_ac < tmp->stats.ac+tmp->magic) {
1502  ac += best_ac; /* Remove last bonus */
1503  best_ac = tmp->stats.ac+tmp->magic;
1504  } else /* To nullify the below effect */
1505  ac += tmp->stats.ac+tmp->magic;
1506  }
1507  if (tmp->stats.dam && tmp->type == BRACERS)
1508  op->stats.dam += (tmp->stats.dam+tmp->magic);
1509  if (tmp->stats.wc)
1510  wc -= tmp->stats.wc;
1511  if (tmp->stats.ac)
1512  ac -= (tmp->stats.ac+tmp->magic);
1513  if (ARMOUR_SPEED(tmp) && ARMOUR_SPEED(tmp)/10.0 < max)
1514  max = ARMOUR_SPEED(tmp)/10.0;
1515  break;
1516  } /* switch tmp->type */
1517  } /* item is equipped */
1518  } FOR_INV_FINISH(); /* for loop of items */
1519 
1520  /* We've gone through all the objects the player has equipped. For many things, we
1521  * have generated intermediate values which we now need to assign.
1522  */
1523 
1524  /* 'total resistance = total protections - total vulnerabilities'.
1525  * If there is an uncursed potion in effect, granting more protection
1526  * than that, we take: 'total resistance = resistance from potion'.
1527  * If there is a cursed (and no uncursed) potion in effect, we take
1528  * 'total resistance = vulnerability from cursed potion'.
1529  */
1530  for (i = 0; i < NROFATTACKS; i++) {
1531  op->resist[i] = prot[i]-vuln[i];
1532  if (potion_resist[i]
1533  && ((potion_resist[i] > op->resist[i]) || (potion_resist[i] < 0)))
1534  op->resist[i] = potion_resist[i];
1535  }
1536 
1537  fix_player(op, &ac, &wc, grace_obj, mana_obj, wc_obj, weapon_speed, added_speed);
1538 
1539  op->speed = op->speed*speed_reduce_from_disease;
1540 
1541  /* Max is determined by armour */
1542  if (op->speed > max)
1543  op->speed = max;
1544 
1545  op->speed += added_speed/10.0;
1546 
1547 
1548  /* Put a lower limit on speed. Note with this speed, you move once every
1549  * 20 ticks or so. This amounts to once every 3 seconds of realtime.
1550  */
1551  if (op->speed < 0.05 && op->type == PLAYER)
1552  op->speed = 0.05;
1553 
1554  /* I want to limit the power of small monsters with big weapons: */
1555  if (op->type != PLAYER
1556  && op->arch != NULL
1557  && op->stats.dam > op->arch->clone.stats.dam*3)
1558  op->stats.dam = op->arch->clone.stats.dam*3;
1559 
1560  /* Prevent overflows of wc - best you can get is ABS(120) - this
1561  * should be more than enough - remember, AC is also in 8 bits,
1562  * so its value is the same.
1563  */
1564  if (wc > 120)
1565  wc = 120;
1566  else if (wc < -120)
1567  wc = -120;
1568  op->stats.wc = wc;
1569 
1570  if (ac > 120)
1571  ac = 120;
1572  else if (ac < -120)
1573  ac = -120;
1574  op->stats.ac = ac;
1575 
1576  /* if for some reason the creature doesn't have any move type,
1577  * give them walking as a default.
1578  * The second case is a special case - to more closely mimic the
1579  * old behaviour - if your flying, your not walking - just
1580  * one or the other.
1581  */
1582  if (op->move_type == 0)
1583  op->move_type = MOVE_WALK;
1584  else if (op->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
1585  op->move_type &= ~MOVE_WALK;
1586 
1587  object_update_speed(op);
1588 }
1589 
1602 int allowed_class(const object *op) {
1603  return op->stats.Dex > 0
1604  && op->stats.Str > 0
1605  && op->stats.Con > 0
1606  && op->stats.Int > 0
1607  && op->stats.Wis > 0
1608  && op->stats.Pow > 0
1609  && op->stats.Cha > 0;
1610 }
1611 
1629 void set_dragon_name(object *pl, const object *abil, const object *skin) {
1630  int atnr = -1; /* attacknumber of highest level */
1631  int level = 0; /* highest level */
1632  int i;
1633 
1634  /* Perhaps do something more clever? */
1635  if (!abil || !skin)
1636  return;
1637 
1638  /* first, look for the highest level */
1639  for (i = 0; i < NROFATTACKS; i++) {
1640  if (atnr_is_dragon_enabled(i)
1641  && (atnr == -1 || abil->resist[i] > abil->resist[atnr])) {
1642  level = abil->resist[i];
1643  atnr = i;
1644  }
1645  }
1646 
1647  /* now if there are equals at highest level, pick the one with focus,
1648  or else at random */
1649  if (atnr_is_dragon_enabled(abil->stats.exp)
1650  && abil->resist[abil->stats.exp] >= level)
1651  atnr = abil->stats.exp;
1652 
1653  level = (int)(level/5.);
1654 
1655  /* now set the new title */
1656  if (pl->contr != NULL) {
1657  player_set_dragon_title(pl->contr, level, attacks[atnr], skin->resist[atnr]);
1658  }
1659 }
1660 
1669 static void dragon_level_gain(object *who) {
1670  object *abil = NULL; /* pointer to dragon ability force*/
1671  object *skin = NULL; /* pointer to dragon skin force*/
1672 
1673  /* now grab the 'dragon_ability'-forces from the player's inventory */
1674  abil = object_find_by_type_and_arch_name(who, FORCE, "dragon_ability_force");
1675  skin = object_find_by_type_and_arch_name(who, FORCE, "dragon_skin_force");
1676  /* if the force is missing -> bail out */
1677  if (abil == NULL)
1678  return;
1679 
1680  /* The ability_force keeps track of maximum level ever achieved.
1681  * New abilties can only be gained by surpassing this max level
1682  */
1683  if (who->level > abil->level) {
1684  /* increase our focused ability */
1685  abil->resist[abil->stats.exp]++;
1686 
1687  if (abil->resist[abil->stats.exp] > 0 && abil->resist[abil->stats.exp]%5 == 0) {
1688  /* time to hand out a new ability-gift */
1689  dragon_ability_gain(who, (int)abil->stats.exp, (int)((1+abil->resist[abil->stats.exp])/5.));
1690  }
1691 
1692  if (abil->last_eat > 0 && atnr_is_dragon_enabled(abil->last_eat)) {
1693  /* apply new ability focus */
1695  "Your metabolism now focuses on %s!",
1696  change_resist_msg[abil->last_eat]);
1697 
1698  abil->stats.exp = abil->last_eat;
1699  abil->last_eat = 0;
1700  }
1701 
1702  abil->level = who->level;
1703  }
1704 
1705  /* last but not least, set the new title for the dragon */
1706  set_dragon_name(who, abil, skin);
1707 }
1708 
1727 object *give_skill_by_name(object *op, const char *skill_name) {
1728  object *skill_obj;
1729  archetype *skill_arch;
1730 
1731  skill_arch = get_archetype_by_skill_name(skill_name, SKILL);
1732  if (!skill_arch) {
1733  LOG(llevError, "add_player_exp: couldn't find skill %s\n", skill_name);
1734  return NULL;
1735  }
1736  skill_obj = arch_to_object(skill_arch); /* never returns NULL. */
1737 
1738  /* clear the flag - exp goes into this bucket, but player
1739  * still doesn't know it.
1740  */
1741  CLEAR_FLAG(skill_obj, FLAG_CAN_USE_SKILL);
1742  skill_obj->stats.exp = 0;
1743  skill_obj->level = 1;
1744  object_insert_in_ob(skill_obj, op);
1745  if (op->contr) {
1746  op->contr->last_skill_ob[skill_obj->subtype] = skill_obj;
1747  op->contr->last_skill_exp[skill_obj->subtype] = -1;
1748  }
1749  return skill_obj;
1750 }
1751 
1768 void player_lvl_adj(object *who, object *op) {
1769  char buf[MAX_BUF];
1770 
1771  assert(who);
1772 
1773  if (!op) /* when rolling stats */
1774  op = who;
1775 
1776  if (op->level < settings.max_level && op->stats.exp >= level_exp(op->level+1, who->expmul)) {
1777  op->level++;
1778 
1779  if (op != NULL && op == who && op->stats.exp > 1 && is_dragon_pl(who))
1780  dragon_level_gain(who);
1781 
1782  /* Only roll these if it is the player (who) that gained the level */
1783  if (op == who && (who->level < 11) && who->type == PLAYER) {
1784  who->contr->levhp[who->level] = die_roll(2, 4, who, PREFER_HIGH)+1;
1785  who->contr->levsp[who->level] = die_roll(2, 3, who, PREFER_HIGH);
1786  who->contr->levgrace[who->level] = die_roll(2, 2, who, PREFER_HIGH)-1;
1787  }
1788 
1789  fix_object(who);
1790  if (op->level > 1) {
1791  if (op->type != PLAYER)
1792  snprintf(buf, sizeof(buf), "You are now level %d in the %s skill.", op->level, op->name);
1793  else
1794  snprintf(buf, sizeof(buf), "You are now level %d.", op->level);
1795 
1797  }
1798  player_lvl_adj(who, op); /* To increase more levels */
1799  } else if (op->level > 1 && op->stats.exp < level_exp(op->level, who->expmul)) {
1800  op->level--;
1801  fix_object(who);
1802  if (op->type != PLAYER)
1803  snprintf(buf, sizeof(buf), "You are now level %d in the %s skill.", op->level, op->name);
1804  else
1805  snprintf(buf, sizeof(buf), "You are now level %d.", op->level);
1806 
1808 
1809  player_lvl_adj(who, op); /* To decrease more levels */
1810  }
1811 }
1812 
1822 int64_t level_exp(int level, double expmul) {
1823  if (level > settings.max_level)
1824  return expmul*levels[settings.max_level];
1825  return expmul*levels[level];
1826 }
1827 
1838 void calc_perm_exp(object *op) {
1839  int64_t p_exp_min;
1840 
1841  /* Ensure that our permanent experience minimum is met.
1842  * permenent_exp_ratio is an integer percentage, we divide by 100
1843  * to get the fraction */
1844  p_exp_min = settings.permanent_exp_ratio*op->stats.exp/100;
1845 
1846  if (op->perm_exp < p_exp_min)
1847  op->perm_exp = p_exp_min;
1848 
1849  /* Cap permanent experience. */
1850  if (op->perm_exp < 0)
1851  op->perm_exp = 0;
1852  else if (op->perm_exp > MAX_EXPERIENCE)
1853  op->perm_exp = MAX_EXPERIENCE;
1854 }
1855 
1856 
1871 static void add_player_exp(object *op, int64_t exp, const char *skill_name, int flag) {
1872  object *skill_obj = NULL;
1873  int64_t limit, exp_to_add;
1874  int i;
1875 
1876  /* prevents some forms of abuse. */
1877  if (op->contr->braced)
1878  exp = exp/5;
1879 
1880  /* Try to find the matching skill.
1881  * We do a shortcut/time saving mechanism first - see if it matches
1882  * chosen_skill. This means we don't need to search through
1883  * the players inventory.
1884  */
1885  if (skill_name) {
1886  if (op->chosen_skill
1887  && op->chosen_skill->type == SKILL
1888  && !strcmp(skill_name, op->chosen_skill->skill))
1889  skill_obj = op->chosen_skill;
1890  else {
1891  for (i = 0; i < NUM_SKILLS; i++)
1892  if (op->contr->last_skill_ob[i]
1893  && !strcmp(op->contr->last_skill_ob[i]->skill, skill_name)) {
1894  skill_obj = op->contr->last_skill_ob[i];
1895  break;
1896  }
1897 
1898  /* Player doesn't have the skill. Check to see what to do, and give
1899  * it to the player if necessary
1900  */
1901  if (!skill_obj) {
1902  if (flag == SK_EXP_NONE)
1903  return;
1904  else if (flag == SK_EXP_ADD_SKILL)
1905  skill_obj = give_skill_by_name(op, skill_name);
1906  }
1907  }
1908  }
1909 
1910  /* Basically, you can never gain more experience in one shot
1911  * than half what you need to gain for next level.
1912  */
1913  exp_to_add = exp;
1914  /*
1915  * Make sure we aren't trying to go backwards when we hit maximum level,
1916  * but make sure we can still add to our permanent experience.
1917  *
1918  * -- Daniel Hawkins 2015-05-24
1919  */
1920  if (op->level == settings.max_level)
1921  limit = levels[op->level] / 2;
1922  else
1923  limit = (levels[op->level+1]-levels[op->level])/2;
1924 
1925  if (exp_to_add > limit)
1926  exp_to_add = limit;
1927 
1928  ADD_EXP(op->stats.exp, (float)exp_to_add*(skill_obj ? skill_obj->expmul : 1));
1930  ADD_EXP(op->perm_exp, (float)exp_to_add*PERM_EXP_GAIN_RATIO*(skill_obj ? skill_obj->expmul : 1));
1931  calc_perm_exp(op);
1932  }
1933 
1934  player_lvl_adj(op, NULL);
1935  if (skill_obj) {
1936  exp_to_add = exp;
1937  /*
1938  * Make sure we aren't trying to go backwards when we hit maximum level,
1939  * but make sure we can still add to our permanent experience.
1940  *
1941  * -- Daniel Hawkins 2015-05-24
1942  */
1943  if (skill_obj->level == settings.max_level)
1944  limit = levels[skill_obj->level] / 2;
1945  else
1946  limit = (levels[skill_obj->level+1]-levels[skill_obj->level])/2;
1947 
1948  if (exp_to_add > limit)
1949  exp_to_add = limit;
1950  ADD_EXP(skill_obj->stats.exp, exp_to_add);
1952  skill_obj->perm_exp += exp_to_add*PERM_EXP_GAIN_RATIO;
1953  calc_perm_exp(skill_obj);
1954  }
1955  player_lvl_adj(op, skill_obj);
1956  }
1957 }
1958 
1974 int64_t check_exp_loss(const object *op, int64_t exp) {
1975  int64_t del_exp;
1976 
1977  if (exp > op->stats.exp)
1978  exp = op->stats.exp;
1980  del_exp = (op->stats.exp-op->perm_exp)*PERM_EXP_MAX_LOSS_RATIO;
1981  if (del_exp < 0)
1982  del_exp = 0;
1983  if (exp > del_exp)
1984  exp = del_exp;
1985  }
1986  return exp;
1987 }
1988 
1999 int64_t check_exp_adjust(const object *op, int64_t exp) {
2000  if (exp < 0)
2001  return check_exp_loss(op, exp);
2002  else
2003  return MIN(exp, MAX_EXPERIENCE-op->stats.exp);
2004 }
2005 
2028 static void subtract_player_exp(object *op, int64_t exp, const char *skill, int flag) {
2029  float fraction = (float)exp/(float)op->stats.exp;
2030  int64_t del_exp;
2031 
2032  FOR_INV_PREPARE(op, tmp)
2033  if (tmp->type == SKILL && tmp->stats.exp) {
2034  if (flag == SK_SUBTRACT_SKILL_EXP && skill && !strcmp(tmp->skill, skill)) {
2035  del_exp = check_exp_loss(tmp, exp);
2036  tmp->stats.exp -= del_exp;
2037  player_lvl_adj(op, tmp);
2038  } else if (flag != SK_SUBTRACT_SKILL_EXP) {
2039  /* only want to process other skills if we are not trying
2040  * to match a specific skill.
2041  */
2042  del_exp = check_exp_loss(tmp, tmp->stats.exp*fraction);
2043  tmp->stats.exp -= del_exp;
2044  player_lvl_adj(op, tmp);
2045  }
2046  }
2047  FOR_INV_FINISH();
2048  if (flag != SK_SUBTRACT_SKILL_EXP) {
2049  del_exp = check_exp_loss(op, exp);
2050  op->stats.exp -= del_exp;
2051  player_lvl_adj(op, NULL);
2052  }
2053 }
2054 
2076 void change_exp(object *op, int64_t exp, const char *skill_name, int flag) {
2077  /* safety */
2078  if (!op) {
2079  LOG(llevError, "change_exp() called for null object!\n");
2080  return;
2081  }
2082 
2083  /* if no change in exp, just return - most of the below code
2084  * won't do anything if the value is 0 anyways.
2085  */
2086  if (exp == 0)
2087  return;
2088 
2089  /* Monsters are easy - we just adjust their exp - we
2090  * don't adjust level, since in most cases it is unrelated to
2091  * the exp they have - the monsters exp represents what its
2092  * worth.
2093  */
2094  if (op->type != PLAYER) {
2095  /* Sanity check */
2096  if (!QUERY_FLAG(op, FLAG_ALIVE))
2097  return;
2098 
2099  /* reset exp to max allowed value. We subtract from
2100  * MAX_EXPERIENCE to prevent overflows. If the player somehow has
2101  * more than max exp, just return.
2102  */
2103  if (exp > 0 && (op->stats.exp > (MAX_EXPERIENCE-exp))) {
2104  exp = MAX_EXPERIENCE-op->stats.exp;
2105  if (exp < 0)
2106  return;
2107  }
2108 
2109  op->stats.exp += exp;
2110  } else { /* Players only */
2111  if (exp > 0)
2112  add_player_exp(op, exp, skill_name, flag);
2113  else
2114  subtract_player_exp(op, FABS(exp), skill_name, flag);
2115  }
2116 }
2117 
2126 void apply_death_exp_penalty(object *op) {
2127  int64_t loss;
2128  int64_t percentage_loss; /* defined by the setting 'death_penalty_percent' */
2129  int64_t level_loss; /* defined by the setting 'death_penalty_levels */
2130 
2131  FOR_INV_PREPARE(op, tmp)
2132  if (tmp->type == SKILL && tmp->stats.exp) {
2133  percentage_loss = tmp->stats.exp*settings.death_penalty_ratio/100;
2134  level_loss = tmp->stats.exp-levels[MAX(0, tmp->level-settings.death_penalty_level)];
2135 
2136  /* With the revised exp system, you can get cases where
2137  * losing several levels would still require that you have more
2138  * exp than you currently have - this is true if the levels
2139  * tables is a lot harder.
2140  */
2141  if (level_loss < 0)
2142  level_loss = 0;
2143 
2144  loss = check_exp_loss(tmp, MIN(level_loss, percentage_loss));
2145 
2146  tmp->stats.exp -= loss;
2147  player_lvl_adj(op, tmp);
2148  }
2149  FOR_INV_FINISH();
2150 
2151  percentage_loss = op->stats.exp*settings.death_penalty_ratio/100;
2152  level_loss = op->stats.exp-levels[MAX(0, op->level-settings.death_penalty_level)];
2153  if (level_loss < 0)
2154  level_loss = 0;
2155  loss = check_exp_loss(op, MIN(level_loss, percentage_loss));
2156 
2157  op->stats.exp -= loss;
2158  player_lvl_adj(op, NULL);
2159 }
2160 
2175 int did_make_save(const object *op, int level, int bonus) {
2176  if (level > MAX_SAVE_LEVEL)
2177  level = MAX_SAVE_LEVEL;
2178 
2179  if ((random_roll(1, 20, op, PREFER_HIGH)+bonus) < savethrow[level])
2180  return 0;
2181  return 1;
2182 }
2183 
2205 void share_exp(object *op, int64_t exp, const char *skill, int flag) {
2206  int shares = 0, count = 0;
2207  player *pl;
2208  partylist *party;
2209 
2210  if (op->type != PLAYER || op->contr->party == NULL) {
2211  change_exp(op, exp, skill, 0);
2212  return;
2213  }
2214 
2215  party = op->contr->party;
2216 
2217  for (pl = first_player; pl != NULL; pl = pl->next) {
2218  if (party && pl->ob->contr->party == party && on_same_map(pl->ob, op)) {
2219  count++;
2220  shares += (pl->ob->level+4);
2221  }
2222  }
2223 
2224  assert(shares > 0);
2225 
2226  if (count == 1 || shares > exp)
2227  change_exp(op, exp, skill, flag);
2228  else {
2229  int64_t share = exp/shares, given = 0, nexp;
2230  for (pl = first_player; pl != NULL; pl = pl->next) {
2231  if (party && pl->ob->contr->party == party && on_same_map(pl->ob, op)) {
2232  nexp = (pl->ob->level+4)*share;
2233  change_exp(pl->ob, nexp, skill, SK_EXP_TOTAL);
2234  given += nexp;
2235  }
2236  }
2237  exp -= given;
2238  /* give any remainder to the player */
2239  change_exp(op, exp, skill, flag);
2240  }
2241 }
2242 
2243 int get_cha_bonus(int stat) {
2245 }
2246 
2247 int get_dex_bonus(int stat) {
2249 }
2250 
2251 int get_thaco_bonus(int stat) {
2253 }
2254 
2257 }
2258 
2259 int get_learn_spell(int stat) {
2261 }
2262 
2263 int get_cleric_chance(int stat) {
2265 }
2266 
2267 int get_turn_bonus(int stat) {
2269 }
2270 
2271 int get_dam_bonus(int stat) {
2273 }
2274 
2275 float get_speed_bonus(int stat) {
2277 }
2278 
2279 int get_fear_bonus(int stat) {
2281 }
2282 
2283 static float get_con_bonus(int stat) {
2285 }
2286 
2287 static float get_sp_bonus(int stat) {
2289 }
2290 
2291 static float get_grace_bonus(int stat) {
2293 }
2294 
2303 static size_t get_index(int stat, size_t max_index) {
2304  size_t index;
2305 
2306  if (stat < 0) {
2307  return 0;
2308  }
2309 
2310  index = (size_t)stat;
2311  return MIN(index, max_index);
2312 }
2313 
2331 static int load_table_int(int **bonuses, FILE *fp, char *bonus_name)
2332 {
2333  char buf[MAX_BUF], *cp;
2334  int on_stat = 0, tmp_bonus;
2335 
2336  *bonuses = calloc(settings.max_stat+1, sizeof(int));
2337 
2338  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2339  if (buf[0] == '#')
2340  continue;
2341 
2342  /* Skip over empty lines */
2343  if (buf[0] == '\n')
2344  continue;
2345 
2346  /* Do not care about opening brace */
2347  if (buf[0] == '{')
2348  continue;
2349 
2350  if (buf[0] == '}') {
2351  if ((on_stat-1) != settings.max_stat) {
2352  LOG(llevError,"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2353  on_stat, settings.max_stat, bonus_name);
2354  return 1;
2355  }
2356  else return 0;
2357  }
2358 
2359  /* If not any of the above values, must be the stat table,
2360  * or so we hope.
2361  */
2362  cp = buf;
2363  while (*cp != 0) {
2364  /* Skip over any non numbers */
2365  while (!isdigit(*cp) && *cp!='.' && *cp!='-' && *cp!='+' && *cp != 0)
2366  cp++;
2367 
2368  if (*cp == 0) break;
2369 
2370  tmp_bonus = atoi(cp);
2371 
2372  if (on_stat > settings.max_stat) {
2373  LOG(llevError,"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2374  buf, bonus_name);
2375  return 1;
2376  }
2377  (*bonuses)[on_stat] = tmp_bonus;
2378  on_stat++;
2379 
2380  /* Skip over any digits, as that is the number we just processed */
2381  while ((isdigit(*cp) || *cp=='-' || *cp=='+') && *cp != 0)
2382  cp++;
2383  }
2384  }
2385  /* This should never happen - we should always get the closing brace */
2386  LOG(llevError,"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2387  return 1;
2388 }
2389 
2407 static int load_table_float(float **bonuses, FILE *fp, char *bonus_name)
2408 {
2409  char buf[MAX_BUF], *cp;
2410  int on_stat = 0;
2411  float tmp_bonus;
2412 
2413  *bonuses = calloc(settings.max_stat+1, sizeof(float));
2414 
2415  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2416  if (buf[0] == '#')
2417  continue;
2418 
2419  /* Skip over empty lines */
2420  if (buf[0] == '\n')
2421  continue;
2422 
2423  /* Do not care about opening brace */
2424  if (buf[0] == '{')
2425  continue;
2426 
2427  if (buf[0] == '}') {
2428  if ((on_stat-1) != settings.max_stat) {
2429  LOG(llevError,"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2430  on_stat, settings.max_stat, bonus_name);
2431  return 1;
2432  }
2433  else return 0;
2434  }
2435 
2436  /* If not any of the above values, must be the stat table,
2437  * or so we hope.
2438  */
2439  cp = buf;
2440  while (*cp != 0) {
2441  /* Skip over any non numbers */
2442  while (!isdigit(*cp) && *cp!='.' && *cp!='-' && *cp!='+' && *cp != 0)
2443  cp++;
2444 
2445  if (*cp == 0) break;
2446 
2447  tmp_bonus = atof(cp);
2448 
2449  if (on_stat > settings.max_stat) {
2450  LOG(llevError,"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2451  buf, bonus_name);
2452  return 1;
2453  }
2454  (*bonuses)[on_stat] = tmp_bonus;
2455  on_stat++;
2456 
2457  /* Skip over any digits, as that is the number we just processed
2458  * since this is floats, also skip over any dots.
2459  */
2460  while ((isdigit(*cp) || *cp=='-' || *cp=='+' || *cp=='.') && *cp != 0)
2461  cp++;
2462  }
2463  }
2464  /* This should never happen - we should always get the closing brace */
2465  LOG(llevError,"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2466  return 1;
2467 }
2468 
2469 
2487 void init_stats(int reload) {
2488  char buf[MAX_BUF], *cp;
2489  int error=0, i, oldmax = settings.max_stat;
2490  FILE *fp;
2491  float *new_float_bonuses[NUM_FLOAT_BONUSES];
2492  int *new_int_bonuses[NUM_INT_BONUSES];
2493 
2494  snprintf(buf, sizeof(buf), "%s/stat_bonus", settings.confdir);
2495 
2496  memset(new_int_bonuses, 0, NUM_INT_BONUSES * sizeof(int));
2497  memset(new_float_bonuses, 0, NUM_FLOAT_BONUSES * sizeof(float));
2498 
2499  if ((fp = fopen(buf, "r")) == NULL) {
2500  LOG(llevError, "Fatal error: could not open experience table (%s)\n", buf);
2501  if (reload) return;
2502  else exit(1);
2503  }
2504  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
2505  if (buf[0] == '#')
2506  continue;
2507 
2508  /* eliminate newline */
2509  if ((cp = strrchr(buf, '\n')) != NULL)
2510  *cp = '\0';
2511 
2512  /* Skip over empty lines */
2513  if (buf[0] == 0)
2514  continue;
2515 
2516  /* Skip over leading spaces */
2517  cp = buf;
2518  while (isspace(*cp) && *cp != 0)
2519  cp++;
2520 
2521  if (!strncasecmp(cp, "max_stat", 8)) {
2522  int newmax = atoi(cp+8);
2523 
2524  /* newmax must be at least MIN_STAT and we do not currently
2525  * cupport decrease max stat on the fly - why this might be possible,
2526  * bounds checking for all objects would be needed, potentionally resetting
2527  * them.
2528  * If this is a reload, then on error, we just return without doing work.
2529  * If this is initial load, having an invalid stat range is an error, so
2530  * exit the program.
2531  */
2532  if (newmax < MIN_STAT || newmax < settings.max_stat) {
2533  LOG(llevError, "Got invalid max_stat (%d) from stat_bonus file\n", newmax);
2534  fclose(fp);
2535  if (reload) return;
2536  else exit(1);
2537  }
2538  settings.max_stat = newmax;
2539  continue;
2540  }
2541  /* max_stat needs to be set before any of the bonus values - we
2542  * need to know how large to make the array.
2543  */
2544  if (settings.max_stat == 0) {
2545  LOG(llevError, "Got bonus line or otherwise unknown value before max stat! (%s)\n",
2546  buf);
2547  fclose(fp);
2548 
2549  if (reload) {
2550  return;
2551  } else {
2552  exit(1);
2553  }
2554  }
2555 
2556  for (i=0; i<NUM_INT_BONUSES; i++) {
2557  if (!strncasecmp(cp, int_bonus_names[i], strlen(int_bonus_names[i]))) {
2558  error = load_table_int(&new_int_bonuses[i], fp, cp);
2559  break;
2560  }
2561  }
2562  /* If we did not find a match in the int bonuses, check the
2563  * float bonuses now.
2564  */
2565  if (i == NUM_INT_BONUSES) {
2566  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2567  if (!strncasecmp(cp, float_bonus_names[i], strlen(float_bonus_names[i]))) {
2568  error = load_table_float(&new_float_bonuses[i], fp, cp);
2569  break;
2570  }
2571  }
2572  /* This may not actually be a critical error */
2573  if (i == NUM_FLOAT_BONUSES) {
2574  LOG(llevError,"Unknown line in stat_bonus file: %s\n", buf);
2575  }
2576  }
2577  if (error) break;
2578  }
2579  fclose(fp);
2580 
2581  /* Make sure that we have load tables for all the bonuses.
2582  * This is critical on initial load, but on reloads, it enusres that
2583  * all the bonus data matches.
2584  */
2585  for (i=0; i<NUM_INT_BONUSES; i++) {
2586  if (!new_int_bonuses[i]) {
2587  LOG(llevError,"No bonus loaded for %s\n", int_bonus_names[i]);
2588  error=2;
2589  }
2590  }
2591 
2592  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2593  if (!new_float_bonuses[i]) {
2594  LOG(llevError,"No bonus loaded for %s\n", float_bonus_names[i]);
2595  error=2;
2596  }
2597  }
2598 
2599  /* If we got an error, we just free up the data we read in and return/exit.
2600  * if no error, we make the tables we just read in into the default
2601  * tables.
2602  */
2603  if (error) {
2604  if (error==1)
2605  LOG(llevError,"Got error reading stat_bonus: %s\n", buf);
2606 
2607  if (reload) {
2608  for (i=0; i<NUM_INT_BONUSES; i++)
2609  if (new_int_bonuses[i]) FREE_AND_CLEAR(new_int_bonuses[i]);
2610  for (i=0; i<NUM_FLOAT_BONUSES; i++)
2611  if (new_float_bonuses[i]) FREE_AND_CLEAR(new_float_bonuses[i]);
2612  settings.max_stat = oldmax;
2613  } else {
2614  exit(1);
2615  }
2616  } else {
2617  /* Everything check out - now copy the data into
2618  * the live arrays.
2619  */
2620  for (i=0; i<NUM_INT_BONUSES; i++) {
2621  free(int_bonuses[i]);
2622  int_bonuses[i] = new_int_bonuses[i];
2623  new_int_bonuses[i] = NULL;
2624  }
2625 
2626  for (i=0; i<NUM_FLOAT_BONUSES; i++) {
2627  free(float_bonuses[i]);
2628  float_bonuses[i] = new_float_bonuses[i];
2629  new_float_bonuses[i] = NULL;
2630  }
2631  }
2632 }
#define INT_THAC0_BONUS
Definition: living.c:65
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
static float get_con_bonus(int stat)
Definition: living.c:2283
Use skill.
Definition: player.h:22
void set_attr_value(living *stats, int attr, int8_t value)
Sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on what attr is (STR to POW)...
Definition: living.c:218
int8_t Int
Definition: living.h:35
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:13
One player.
Definition: player.h:92
#define FLAG_SEE_IN_DARK
if set ob not effected by darkness
Definition: define.h:338
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
#define WEAPON_SPEED(xyz)
Definition: define.h:482
int8_t ac
Armour Class, how hard to hit, the lower the better.
Definition: living.h:37
#define MOVE_WALK
Object walks.
Definition: define.h:407
int64_t check_exp_adjust(const object *op, int64_t exp)
Returns the maximum experience the object can gain or lose.
Definition: living.c:1999
MoveType move_type
Type of movement this object uses.
Definition: object.h:424
#define FLOAT_CON_BONUS
This is basically same as above, but for bonuses in which we store the value as a float...
Definition: living.c:85
void drain_stat(object *op)
Drains a random stat from op.
Definition: living.c:712
int16_t gen_hp
Bonuses to regeneration speed of hp.
Definition: player.h:113
See Ring.
Definition: object.h:185
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:322
int64_t level_exp(int level, double expmul)
Returns how much experience is needed for a player to become the given level.
Definition: living.c:1822
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
const char *const restore_msg[NUM_STATS]
Message when a player has a stat restored.
Definition: living.c:150
Eneq((at)csd.uu.se): Id for close_container archetype.
Definition: object.h:229
uint8_t spell_encumbrance
Encumbrance effects spells.
Definition: global.h:266
#define SET_FLAG(xyz, p)
Definition: define.h:223
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.c:210
See Bracers.
Definition: object.h:217
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
uint32_t braced
Will not move if braced, only attack.
Definition: player.h:124
static float get_grace_bonus(int stat)
Definition: living.c:2291
int get_dam_bonus(int stat)
Definition: living.c:2271
#define INT_TURN_BONUS
Definition: living.c:59
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_LOSS
the player gaining or losing these attacktypes not being a victim of an attacktype.
Definition: newclient.h:533
uint8_t death_penalty_level
How many levels worth of exp may be lost on one death.
Definition: global.h:258
#define FLAG_USE_ARMOUR
(Monster) can wear armour/shield/helmet
Definition: define.h:296
See Cloak.
Definition: object.h:204
One party.
Definition: party.h:10
#define ADD_EXP(exptotal, exp)
Handy little macro that adds exp and keeps it within bounds.
Definition: living.c:42
Definition: living.h:14
int16_t gen_grace
Bonuses to regeneration speed of grace.
Definition: player.h:116
#define PERM_EXP_MAX_LOSS_RATIO
Definition: config.h:288
int16_t max_level
This is read out of exp_table.
Definition: global.h:300
int16_t maxgrace
Maximum grace.
Definition: living.h:44
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
#define NDI_BLUE
Actually, it is Dodger Blue.
Definition: newclient.h:226
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:168
object clone
An object from which to do object_copy()
Definition: object.h:470
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
Definition: living.h:17
See Weapon.
Definition: object.h:119
See Helmet.
Definition: object.h:136
const char * slaying
Which race to do double damage to.
Definition: object.h:319
#define FLOAT_DEX_BONUS
Definition: living.c:86
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_GAIN
Atacktypes here refer to.
Definition: newclient.h:532
#define FLAG_STEALTH
Will wake monsters with less range.
Definition: define.h:313
int object_check_move_on(object *op, object *originator)
Checks if any objects has a move_type that matches objects that effect this object on this space...
Definition: object.c:2835
object * ranges[range_size]
Object for each range.
Definition: player.h:103
uint8_t subtype
Subtype of object.
Definition: object.h:339
See Rod.
Definition: object.h:109
int64_t exp
Experience.
Definition: living.h:46
void change_luck(object *op, int value)
Alter the object&#39;s luck.
Definition: living.c:791
double expmul
needed experience = (calc_exp*expmul) - means some races/classes can need less/more exp to gain level...
Definition: object.h:395
Misc items.
Definition: player.h:20
#define TRUE
Definition: compat.h:10
See Girdle.
Definition: object.h:223
object * arch_present_in_ob(const archetype *at, const object *op)
Searches for any objects with a matching archetype in the inventory of the given object.
Definition: object.c:3061
Various statistics of objects.
Definition: living.h:34
int64_t check_exp_loss(const object *op, int64_t exp)
This function checks to make sure that object &#39;op&#39; can lose &#39;exp&#39; experience.
Definition: living.c:1974
See Amulet.
Definition: object.h:139
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.c:313
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:343
#define MAX(x, y)
Definition: compat.h:20
uint8_t death_penalty_ratio
Hhow much exp should be lost at death.
Definition: global.h:257
int16_t sp
Spell points.
Definition: living.h:41
uint32_t get_weight_limit(int stat)
Definition: living.c:2255
#define MAX_EXPERIENCE
Definition: living.c:99
Global type definitions and header inclusions.
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:344
See Boots.
Definition: object.h:212
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
static const char *const drain_msg[NUM_STATS]
Message when a player is drained of a stat.
Definition: living.c:139
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
See Wand & Staff.
Definition: object.h:220
int16_t maxsp
Max spell points.
Definition: living.h:42
#define MIN(x, y)
Definition: compat.h:17
int8_t Con
Definition: living.h:35
int16_t hp
Hit Points.
Definition: living.h:39
partylist * party
Party this player is part of.
Definition: player.h:186
#define IS_MANA_SKILL(num)
Like IS_COMBAT_SKILL above, but instead this is used to determine how many mana points the player has...
Definition: skills.h:107
object * give_skill_by_name(object *op, const char *skill_name)
Given the skill name skill_name, we find the skill archetype/object, set appropriate values...
Definition: living.c:1727
Allows the use of a skill.
Definition: object.h:189
#define MIN_STAT
The minimum legal value of any stat.
Definition: define.h:33
#define FREE_PLAYER_LOAD_PERCENT
Definition: config.h:98
#define FLAG_UNDEAD
Monster is 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)
Complement to fix_object() for player.
Definition: living.c:892
int get_cha_bonus(int stat)
Definition: living.c:2243
struct obj * chosen_skill
The skill chosen to use.
Definition: object.h:386
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
int change_abil(object *op, object *tmp)
Permanently alters an object&#39;s stats/flags based on another object.
Definition: living.c:394
#define NDI_RED
Definition: newclient.h:224
int16_t maxhp
Max hit points.
Definition: living.h:40
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
End of a bad effect.
Definition: newclient.h:561
living applied_stats
Stat changes due to gear or skills.
Definition: player.h:152
#define NUM_FLOAT_BONUSES
Definition: living.c:89
void player_lvl_adj(object *who, object *op)
For the new exp system.
Definition: living.c:1768
See Shooting Weapon.
Definition: object.h:118
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:345
#define MSG_TYPE_ATTRIBUTE_MOVE
A change in the movement type of the player.
Definition: newclient.h:554
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
#define FLAG_REFL_SPELL
Spells (some) will reflect from object.
Definition: define.h:275
const char *const gain_msg[NUM_STATS]
Message when a player increases permanently a stat.
Definition: living.c:161
static const int savethrow[MAX_SAVE_LEVEL+1]
Probability to avoid something.
Definition: living.c:113
int get_turn_bonus(int stat)
Definition: living.c:2267
static int load_table_int(int **bonuses, FILE *fp, char *bonus_name)
This loads up a stat table from the file - basically, it keeps processing until it gets the closing b...
Definition: living.c:2331
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
#define SK_EXP_TOTAL
Give player exp to total, no skill.
Definition: skills.h:80
int16_t gen_sp
Bonuses to regeneration speed of sp.
Definition: player.h:114
#define MOVE_SWIM
Swimming object.
Definition: define.h:411
#define MSG_TYPE_ATTRIBUTE_PROTECTION_GAIN
Protections in this.
Definition: newclient.h:542
uint8_t search_items
Search_items command.
Definition: global.h:265
static void subtract_player_exp(object *op, int64_t exp, const char *skill, int flag)
Subtracts experience from player.
Definition: living.c:2028
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:322
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:408
const char *const statname[NUM_STATS]
Name of stats.
Definition: living.c:183
int8_t Wis
Definition: living.h:35
int is_dragon_pl(const object *op)
Checks if player is a dragon.
Definition: player.c:114
char search_str[MAX_BUF]
Item we are looking for.
Definition: player.h:192
#define snprintf
Definition: win32.h:46
#define ARCH_DEPLETION
Archetype for depletion.
Definition: object.h:579
void drain_specific_stat(object *op, int deplete_stats)
Drain a specified stat from op.
Definition: living.c:724
#define MSG_TYPE_ATTRIBUTE
Changes to attributes (stats, resistances, etc)
Definition: newclient.h:380
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
int16_t dam
How much damage this object does when hitting.
Definition: living.h:45
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.c:121
void change_attr_value(living *stats, int attr, int8_t value)
Like set_attr_value(), but instead the value (which can be negative) is added to the specified stat...
Definition: living.c:264
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:257
int32_t carrying
How much weight this object contains.
Definition: object.h:367
archetype * get_archetype_by_skill_name(const char *skill, int type)
Retrieves an archetype by skill name and type.
Definition: arch.c:107
int get_fear_bonus(int stat)
Definition: living.c:2279
const char * name
The name of the object, obviously...
Definition: object.h:311
living orig_stats
Permanent real stats of player.
Definition: player.h:148
int64_t perm_exp
Permanent exp.
Definition: object.h:369
#define ARMOUR_SPEED(xyz)
Definition: define.h:480
int allowed_class(const object *op)
Returns true if the given player is a legal class.
Definition: living.c:1602
#define INT_WEIGHT_LIMIT
Definition: living.c:66
static float get_sp_bonus(int stat)
Definition: living.c:2287
struct obj * current_weapon
Pointer to the weapon currently used.
Definition: object.h:370
#define PERM_EXP_GAIN_RATIO
This determine how many entries are stored in the kill log.
Definition: config.h:287
#define MAX_PLAYER_SPEED
Definition: config.h:97
int8_t Cha
Definition: living.h:35
EXTERN const char *const change_resist_msg[NROFATTACKS]
Definition: attack.h:135
Number of statistics.
Definition: living.h:18
See Potion.
Definition: object.h:111
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
void add_statbonus(object *op)
Adds stat-bonuses given by the class which the player has chosen.
Definition: living.c:863
#define MIN_PLAYER_SPEED
Definition: config.h:96
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:301
#define INT_DAM_BONUS
Definition: living.c:64
#define MSG_TYPE_ATTRIBUTE_LEVEL_GAIN
Definition: newclient.h:564
static const char * float_bonus_names[NUM_FLOAT_BONUSES]
Definition: living.c:91
#define ATNR_PHYSICAL
Definition: attack.h:49
Praying.
Definition: skills.h:49
static void dragon_level_gain(object *who)
This function is called when a dragon-player gains an overall level.
Definition: living.c:1669
static float * float_bonuses[NUM_FLOAT_BONUSES]
Definition: living.c:90
int8_t luck
Affects thaco and ac from time to time.
Definition: living.h:38
#define AT_PHYSICAL
Definition: attack.h:76
float speed
The overall speed of this object.
Definition: object.h:328
int on_same_map(const object *op1, const object *op2)
Checks whether 2 objects are on the same map or not.
Definition: map.c:2627
#define NUM_INT_BONUSES
Definition: living.c:67
#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:61
static int * int_bonuses[NUM_INT_BONUSES]
Definition: living.c:69
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.c:2076
#define INT_FEAR_BONUS
The definitions below are indexes into the bonuses[] array.
Definition: living.c:58
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define FLOAT_SP_BONUS
Definition: living.c:87
int strncasecmp(const char *s1, const char *s2, int n)
Case-insensitive comparaison of strings.
Definition: porting.c:224
int16_t encumbrance
How much our player is encumbered.
Definition: player.h:179
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:167
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:563
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
int32_t last_eat
How long since we last ate.
Definition: object.h:356
#define NUM_SKILLS
This is the highest number skill in the table +1 This is used to store pointers to the actual skills ...
Definition: skills.h:71
int8_t wc
Weapon Class, how skilled, the lower the better.
Definition: living.h:36
const char * confdir
Configuration files.
Definition: global.h:243
See Container.
Definition: object.h:231
signed __int64 int64_t
Definition: win32.h:168
#define FLAG_READY_WEAPON
(Monster or Player) has a weapon readied
Definition: define.h:335
#define DIFF_MSG(flag, subtype1, subtype2, msg1, msg2)
Rather than having a whole bunch of if (flag) draw.
Definition: living.c:369
int8_t Str
Definition: living.h:35
void calc_perm_exp(object *op)
Ensure that the permanent experience requirements in an exp object are met.
Definition: living.c:1838
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:341
object * ob
The object representing the player.
Definition: player.h:158
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START
Start of a good effect to the player.
Definition: newclient.h:566
const char *const lose_msg[NUM_STATS]
Message when a player decreases permanently a stat.
Definition: living.c:172
uint8_t permanent_exp_ratio
How much exp should be &#39;permenant&#39; and unable to be lost.
Definition: global.h:256
#define INT_DEX_BONUS
Definition: living.c:63
unsigned int uint32_t
Definition: win32.h:162
See Player.
Definition: object.h:107
static void add_player_exp(object *op, int64_t exp, const char *skill_name, int flag)
Add experience to a player - exp should only be positive.
Definition: living.c:1871
See Shield.
Definition: object.h:135
#define INT_CLERIC_CHANCE
Definition: living.c:60
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:372
#define PREFER_HIGH
Definition: define.h:599
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:342
int64_t * levels
Number of levels for which we have experience.
Definition: exp.c:26
#define FLAG_BLIND
If set, object cannot see (visually)
Definition: define.h:337
#define RANDOM()
Definition: define.h:679
int16_t grace
Grace.
Definition: living.h:43
signed char int8_t
Type definitions for fixed-size integer types.
Definition: win32.h:158
Also see SKILL_TOOL (74) below.
Definition: object.h:143
#define INT_CHA_BONUS
Definition: living.c:62
void player_set_dragon_title(struct pl *pl, int level, const char *attack, int skin_resist)
Updates the title of a dragon player to reflect the current level, attack type, and resistances...
Definition: player.c:194
living stats
Str, Con, Dex, etc.
Definition: object.h:368
#define MSG_TYPE_ATTRIBUTE_STAT_GAIN
Definition: newclient.h:562
int8_t Dex
Definition: living.h:35
struct archt * arch
Pointer to archetype.
Definition: object.h:412
#define MSG_TYPE_ATTRIBUTE_LEVEL_LOSS
Definition: newclient.h:565
void init_stats(int reload)
This loads statistic bonus/penalties from the stat_bonus file.
Definition: living.c:2487
static size_t get_index(int stat, size_t max_index)
Limits a stat value to [0..max_index].
Definition: living.c:2303
Only for debugging purposes.
Definition: logger.h:13
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:126
struct Settings settings
Server settings.
Definition: init.c:40
static int load_table_float(float **bonuses, FILE *fp, char *bonus_name)
This loads up a stat table from the file - basically, it keeps processing until it gets the closing b...
Definition: living.c:2407
int remove_depletion(object *op, int level)
Remove depletion from op, if present, and warn player of such restorations.
Definition: living.c:751
#define SK_EXP_ADD_SKILL
Give the player the skill.
Definition: skills.h:79
#define SK_EXP_NONE
Player gets nothing.
Definition: skills.h:81
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
#define FLAG_LIFESAVE
Saves a players&#39; life once, then destr.
Definition: define.h:306
int64_t last_skill_exp[NUM_SKILLS]
Last exp sent to client.
Definition: player.h:138
#define FLAG_MAKE_INVIS
(Item) gives invisibility when applied
Definition: define.h:329
void apply_death_exp_penalty(object *op)
Applies a death penalty experience, the size of this is defined by the settings death_penalty_percent...
Definition: living.c:2126
Bow.
Definition: player.h:18
int16_t gen_sp_armour
Penalty to sp regen from armour.
Definition: player.h:115
#define MAX_SAVE_LEVEL
Definition: living.c:103
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
EXTERN player * first_player
First player.
Definition: global.h:117
struct pl * next
Pointer to next player, NULL if this is last.
Definition: player.h:93
int8_t glow_radius
indicates the glow radius of the object
Definition: object.h:364
int8_t Pow
Definition: living.h:35
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
int get_cleric_chance(int stat)
Definition: living.c:2263
See Gloves.
Definition: object.h:213
#define MOVE_FLY_HIGH
High flying object.
Definition: define.h:409
void dragon_ability_gain(object *who, int atnr, int level)
When a dragon-player gains a new stage of evolution, he gets some treasure.
Definition: main.c:345
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
A force, holding the effect of a resistance potion.
Definition: object.h:225
int16_t item_power
Total item power of objects equipped.
Definition: player.h:117
int get_learn_spell(int stat)
Definition: living.c:2259
int did_make_save(const object *op, int level, int bonus)
This function takes an object (monster/player, op), and determines if it makes a basic save throw by ...
Definition: living.c:2175
object * last_skill_ob[NUM_SKILLS]
Exp objects sent to client.
Definition: player.h:137
Structure containing object statistics.
#define MSG_TYPE_ATTRIBUTE_RACE
Race-related changes.
Definition: newclient.h:557
void set_dragon_name(object *pl, const object *abil, const object *skin)
Set the new dragon name after gaining levels or changing ability focus (later this can be extended to...
Definition: living.c:1629
#define MSG_TYPE_ATTRIBUTE_PROTECTION_LOSS
context are pretty generic - things like reflection or lifesave are also under the protection categor...
Definition: newclient.h:543
#define SK_SUBTRACT_SKILL_EXP
Used when removing exp.
Definition: skills.h:82
void share_exp(object *op, int64_t exp, const char *skill, int flag)
Gives experience to a player/monster, sharing it with party if applicable.
Definition: living.c:2205
void remove_statbonus(object *op)
Subtracts stat-bonuses given by the class which the player has chosen.
Definition: living.c:840
void esrv_update_spells(player *pl)
This looks for any spells the player may have that have changed their stats.
Definition: main.c:358
#define IS_COMBAT_SKILL(num)
This macro is used in fix_object() to define if this is a sill that should be used to calculate wc&#39;s ...
Definition: skills.h:92
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.c:42
#define AT_CONFUSION
Definition: attack.h:81
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:203
int8_t levgrace[11]
What grace bonus the player gained on that level.
Definition: player.h:169
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Find object in inventory by type and archetype name.
Definition: object.c:4168
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
End of a good effect.
Definition: newclient.h:569
See Breastplate Armor.
Definition: object.h:120
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.c:194
#define FLAG_REFL_MISSILE
Arrows will reflect from object.
Definition: define.h:273
int get_dex_bonus(int stat)
Definition: living.c:2247
int16_t level
Level of creature or object.
Definition: object.h:351
#define FLOAT_GRACE_BONUS
Definition: living.c:88
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.c:1120
float weapon_speed
The overall speed of this object.
Definition: object.h:330
#define IS_GRACE_SKILL(num)
Currently only one of these, but put the define here to make it easier to expand it in the future...
Definition: skills.h:121
See Disease.
Definition: object.h:244
float get_speed_bonus(int stat)
Definition: living.c:2275
static const char * int_bonus_names[NUM_INT_BONUSES]
Following array corresponds to the defines above, but are the text names as found in the file...
Definition: living.c:75
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.c:1129
int16_t digestion
Any bonuses/penalties to digestion.
Definition: player.h:112
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
Start of a bad effect to the player.
Definition: newclient.h:558
const char *const attacks[NROFATTACKS]
Attack type names.
Definition: living.c:129
int8_t body_used[NUM_BODY_LOCATIONS]
Calculated value based on items equipped.
Definition: object.h:373
int atnr_is_dragon_enabled(int attacknr)
Determine if the attacktype represented by the specified attack-number is enabled for dragon players...
Definition: player.c:95
int32_t food
How much food in stomach.
Definition: living.h:47
Definition: object.h:224
int get_thaco_bonus(int stat)
Definition: living.c:2251
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Ensures that all stats (str/dex/con/wis/cha/int) are within the passed in range of min_stat and max_s...
Definition: living.c:354