35 static size_t get_index(
int stat,
size_t max_index);
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)
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
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",
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
93 "con_hp_bonus",
"dex_speed_bonus",
"pow_int_sp_bonus",
"wis_pow_grace_bonus"
100 #define MAX_EXPERIENCE levels[settings.max_level]
104 #define MAX_SAVE_LEVEL 110
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
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",
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."
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."
163 "You feel stronger.",
164 "You feel more agile.",
167 "You seem to look better.",
169 "You feel more potent."
176 "You feel less healthy!",
180 "You feel less potent!"
298 LOG(
llevError,
"Invalid attribute in change_attr_value: %d\n", attr);
360 else if (v < min_stat)
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);
404 memcpy(&refop,
op,
sizeof(
object));
416 nstat = flag*i+ostat;
423 if (nstat < 1 && i*flag < 0)
428 if (nstat != ostat) {
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;
457 op->move_type &= ~
tmp->move_type;
472 "Your hands begin to glow red.",
473 "Your hands stop glowing red.");
478 "You feel very protected.",
479 "You don't feel protected anymore.");
484 "A magic force shimmers around you.",
485 "The magic force fades away.");
490 "You feel more safe now, somehow.",
491 "Suddenly you feel less safe, somehow.");
507 "You start to float in the air!",
508 "You float down to the ground.");
516 "You soar into the air!.",
518 "You float down to the ground."));
522 "You feel ready for a swim",
523 "You no longer feel like swimming");
543 if (
op->arch->clone.race)
554 "You walk more quietly.",
555 "You walk more noisily.");
560 "You become transparent.",
561 "You can see yourself.");
575 op->contr->do_los = 1;
584 op->contr->do_los = 1;
592 op->contr->do_los = 1;
594 "Your vision is better in the dark.",
595 "You see less well in the dark.");
606 op->contr->do_los = 1;
614 op->contr->do_los = 1;
619 if (
tmp->stats.luck) {
622 "You feel more lucky.",
623 "You feel less lucky.");
629 "You feel much more healthy!",
630 "You feel much less healthy!");
636 "You feel one with the powers of magic!",
637 "You suddenly feel very mundane.");
644 "You feel closer to your god!",
645 "You suddenly feel less holy.");
651 "You feel more confident in combat.",
652 "You feel less confident in combat.");
658 "You feel more confident in your dodging skills.",
659 "You feel less confident in your dodging skills.");
665 "You feel like you're moving faster.",
666 "You feel like you're moving more slowly.");
672 "You feel your digestion slowing down.",
673 "You feel your digestion speeding up.");
681 if (
op->resist[i] != refop.
resist[i]) {
683 if (
op->resist[i] > refop.
resist[i])
685 "Your resistance to %s rises to %d%%.",
689 "Your resistance to %s drops to %d%%.",
699 if ((curr_val >
MIN_STAT && i < 0) || (curr_val < settings.max_stat && i > 0)) {
785 return (
count == 0) ? 0 : 1;
820 if (new_luck >= -100 && new_luck <= 100) {
822 tmp->stats.luck = new_luck;
825 if (!
tmp->stats.luck) {
832 int diff =
tmp->stats.luck > 0 ? -1 : 1;
833 op->stats.luck += diff;
834 tmp->stats.luck += diff;
847 op->stats.Str -=
op->arch->clone.stats.Str;
848 op->stats.Dex -=
op->arch->clone.stats.Dex;
849 op->stats.Con -=
op->arch->clone.stats.Con;
850 op->stats.Wis -=
op->arch->clone.stats.Wis;
851 op->stats.Pow -=
op->arch->clone.stats.Pow;
852 op->stats.Cha -=
op->arch->clone.stats.Cha;
853 op->stats.Int -=
op->arch->clone.stats.Int;
854 op->contr->orig_stats.Str -=
op->arch->clone.stats.Str;
855 op->contr->orig_stats.Dex -=
op->arch->clone.stats.Dex;
856 op->contr->orig_stats.Con -=
op->arch->clone.stats.Con;
857 op->contr->orig_stats.Wis -=
op->arch->clone.stats.Wis;
858 op->contr->orig_stats.Pow -=
op->arch->clone.stats.Pow;
859 op->contr->orig_stats.Cha -=
op->arch->clone.stats.Cha;
860 op->contr->orig_stats.Int -=
op->arch->clone.stats.Int;
870 op->stats.Str +=
op->arch->clone.stats.Str;
871 op->stats.Dex +=
op->arch->clone.stats.Dex;
872 op->stats.Con +=
op->arch->clone.stats.Con;
873 op->stats.Wis +=
op->arch->clone.stats.Wis;
874 op->stats.Pow +=
op->arch->clone.stats.Pow;
875 op->stats.Cha +=
op->arch->clone.stats.Cha;
876 op->stats.Int +=
op->arch->clone.stats.Int;
877 op->contr->orig_stats.Str +=
op->arch->clone.stats.Str;
878 op->contr->orig_stats.Dex +=
op->arch->clone.stats.Dex;
879 op->contr->orig_stats.Con +=
op->arch->clone.stats.Con;
880 op->contr->orig_stats.Wis +=
op->arch->clone.stats.Wis;
881 op->contr->orig_stats.Pow +=
op->arch->clone.stats.Pow;
882 op->contr->orig_stats.Cha +=
op->arch->clone.stats.Cha;
883 op->contr->orig_stats.Int +=
op->arch->clone.stats.Int;
898 static void fix_player(
object *
op,
int *
ac,
int *wc,
const object *grace_obj,
const object *mana_obj,
const object *wc_obj,
int weapon_speed,
float added_speed)
907 pl_level =
op->level;
920 for (i = 1,
op->stats.maxhp = 0; i <= pl_level && i <= 10; i++) {
925 if (tmpf < 1.0) tmpf = 1.0;
933 op->stats.maxhp = (
int)(maxhp + 0.5);
935 op->stats.maxhp += 2 * (
op->level - 10);
937 op->stats.maxhp +=
op->arch->clone.stats.maxhp;
939 if (
op->stats.hp >
op->stats.maxhp)
940 op->stats.hp =
op->stats.maxhp;
946 if (!mana_obj || !mana_obj->
level) {
949 float sp_tmp = 0.0, mana_bonus;
952 mana_lvl_max = (mana_obj->
level >10 ? 10: mana_obj->
level);
955 for (i = 1; i <= mana_lvl_max; i++) {
958 stmp =
op->contr->levsp[i] + mana_bonus;
961 if (i == 1) stmp += mana_bonus;
969 op->stats.maxsp = (
int)sp_tmp+
op->arch->clone.stats.maxsp;
972 op->stats.maxsp += 2 * (mana_obj->
level - 10);
976 if (
op->stats.sp >
op->stats.maxsp*2)
977 op->stats.sp =
op->stats.maxsp*2;
980 if (!grace_obj || !grace_obj->
level) {
981 op->stats.maxgrace = 1;
988 float sp_tmp = 0.0, grace_bonus;
992 for (i = 1; i <= grace_obj->
level && i <= 10; i++) {
993 float grace_tmp =
op->contr->levgrace[i] + grace_bonus;
997 grace_tmp += grace_bonus;
1001 sp_tmp += grace_tmp;
1003 op->stats.maxgrace = (
int)sp_tmp+
op->arch->clone.stats.maxgrace;
1007 op->stats.maxgrace += 2 * (grace_obj->
level - 10);
1011 if (
op->contr->braced) {
1029 if (wc_obj && wc_obj->
level >= 1) {
1031 int wc_increase_rate;
1033 wc_increase_rate = wc_in?atoi(wc_in):5;
1034 assert(wc_increase_rate != 0);
1037 (*wc) -= (wc_obj->
level-1)/wc_increase_rate;
1038 op->stats.dam += (wc_obj->
level-1)/4;
1044 if (
op->stats.dam < 1)
1052 if (
op->attacktype == 0)
1053 op->attacktype =
op->arch->clone.attacktype;
1070 if (
op->contr->character_load >= 1.0)
1071 op->contr->character_load = 1.0;
1082 op->contr->character_load = 0;
1088 op->weapon_speed += 0.005*wc_obj->
level;
1090 op->weapon_speed += 0.005*
op->level;
1096 op->weapon_speed -=
op->contr->character_load*0.2;
1098 if (
op->weapon_speed < 0.05)
1099 op->weapon_speed = 0.05;
1128 float max = 9, added_speed = 0, speed_reduce_from_disease = 1;
1129 int weapon_speed = 0;
1130 int best_wc = 0, best_ac = 0, wc = 0,
ac = 0;
1132 const object *grace_obj = NULL, *mana_obj = NULL, *wc_obj = NULL;
1141 op->contr->encumbrance = 0;
1144 op->contr->digestion = 0;
1145 op->contr->gen_hp = 0;
1146 op->contr->gen_sp = 0;
1147 op->contr->gen_grace = 0;
1148 op->contr->gen_sp_armour = 10;
1149 op->contr->item_power = 0;
1160 memcpy(
op->body_used,
op->body_info,
sizeof(
op->body_info));
1162 if (
op->slaying != NULL) {
1185 op->path_attuned =
op->arch->clone.path_attuned;
1186 op->path_repelled =
op->arch->clone.path_repelled;
1187 op->path_denied =
op->arch->clone.path_denied;
1188 op->glow_radius =
op->arch->clone.glow_radius;
1189 op->move_type =
op->arch->clone.move_type;
1190 op->chosen_skill = NULL;
1195 memcpy(&
op->resist, &
op->arch->clone.resist,
sizeof(
op->resist));
1198 if (
op->resist[i] > 0)
1199 prot[i] =
op->resist[i], vuln[i] = 0;
1201 vuln[i] = -(
op->resist[i]), prot[i] = 0;
1202 potion_resist[i] = 0;
1205 wc =
op->arch->clone.stats.wc;
1206 op->stats.dam =
op->arch->clone.stats.dam;
1216 ac =
MAX(-10,
op->arch->clone.stats.ac-
op->level/3);
1219 ac =
op->arch->clone.stats.ac;
1221 op->stats.luck =
op->arch->clone.stats.luck;
1222 op->speed =
op->arch->clone.speed;
1232 if (
tmp->glow_radius >
op->glow_radius)
1233 op->glow_radius =
tmp->glow_radius;
1248 else if (
tmp->level > mana_obj->level)
1254 else if (
tmp->level > grace_obj->
level)
1313 op->contr->digestion +=
tmp->stats.food;
1314 op->contr->gen_hp +=
tmp->stats.hp;
1315 op->contr->gen_sp +=
tmp->stats.sp;
1316 op->contr->gen_grace +=
tmp->stats.grace;
1317 op->contr->gen_sp_armour +=
tmp->gen_sp_armour;
1326 op->contr->item_power +=
tmp->item_power;
1334 op->body_used[i] +=
tmp->body_info[i];
1339 if (((
float)
tmp->last_sp/100.0) < speed_reduce_from_disease)
1340 speed_reduce_from_disease = (float)
tmp->last_sp/100.0;
1354 if (potion_resist[i])
1355 potion_resist[i] =
MAX(potion_resist[i],
tmp->resist[i]);
1357 potion_resist[i] =
tmp->resist[i];
1358 }
else if (
tmp->resist[i] > 0)
1359 prot[i] += ((100-prot[i])*
tmp->resist[i])/100;
1360 else if (
tmp->resist[i] < 0)
1361 vuln[i] += ((100-vuln[i])*(-
tmp->resist[i]))/100;
1367 op->attacktype |=
tmp->attacktype;
1369 op->path_attuned |=
tmp->path_attuned;
1370 op->path_repelled |=
tmp->path_repelled;
1371 op->path_denied |=
tmp->path_denied;
1372 op->stats.luck +=
tmp->stats.luck;
1373 op->move_type |=
tmp->move_type;
1405 added_speed += (float)
tmp->stats.exp/3.0;
1408 switch (
tmp->type) {
1418 if (
op->chosen_skill) {
1419 LOG(
llevDebug,
"fix_object, op %s has multiple skills applied\n",
op->name);
1421 op->chosen_skill =
tmp;
1422 if (
tmp->stats.dam > 0) {
1425 if (weapon_speed < 0)
1427 op->stats.dam +=
tmp->stats.dam*(1+(
op->chosen_skill->level/9));
1428 op->stats.dam +=
tmp->magic;
1431 wc -= (
tmp->stats.wc+
tmp->magic);
1433 if (
tmp->slaying != NULL) {
1434 if (
op->slaying != NULL)
1442 op->contr->encumbrance += (
int)3*
tmp->weight/1000;
1448 if (
op->chosen_skill) {
1449 LOG(
llevDebug,
"fix_object, op %s has multiple skills applied\n",
op->name);
1451 op->chosen_skill =
tmp;
1458 op->contr->encumbrance += (
int)
tmp->weight/2000;
1468 wc -=
tmp->stats.wc;
1470 op->stats.dam += (
tmp->stats.dam+
tmp->magic);
1476 wc -=
tmp->stats.wc;
1477 if (
tmp->stats.ac &&
tmp->stats.ac+
tmp->magic > 0)
1479 op->stats.dam += (
tmp->stats.dam+
tmp->magic);
1481 if (weapon_speed < 0)
1483 if (
tmp->slaying != NULL) {
1484 if (
op->slaying != NULL)
1492 op->current_weapon =
tmp;
1494 op->contr->encumbrance += (
int)3*
tmp->weight/1000;
1499 op->contr->encumbrance += (
int)
tmp->weight/1000;
1507 if (
tmp->stats.wc) {
1509 if (
tmp->type ==
BRACERS &&
op->type ==
PLAYER &&
op->arch->name && strcmp(
op->arch->name,
"serpentman_player") == 0)
1514 wc -=
tmp->stats.wc;
1516 else if (best_wc < tmp->stats.wc) {
1518 best_wc =
tmp->stats.wc;
1519 wc -=
tmp->stats.wc;
1522 if (
tmp->stats.ac) {
1529 if (
tmp->type ==
BRACERS &&
op->type ==
PLAYER &&
op->arch->name && strcmp(
op->arch->name,
"serpentman_player") == 0)
1536 else if (best_ac < tmp->stats.ac+
tmp->magic) {
1538 best_ac =
tmp->stats.ac+
tmp->magic;
1543 op->stats.dam += (
tmp->stats.dam+
tmp->magic);
1562 op->resist[i] = prot[i]-vuln[i];
1563 if (potion_resist[i]
1564 && ((potion_resist[i] >
op->resist[i]) || (potion_resist[i] < 0)))
1565 op->resist[i] = potion_resist[i];
1568 fix_player(
op, &
ac, &wc, grace_obj, mana_obj, wc_obj, weapon_speed, added_speed);
1570 op->speed =
op->speed*speed_reduce_from_disease;
1573 if (
op->speed >
max)
1576 op->speed += added_speed/10.0;
1598 if (added_speed >= 0)
1599 LOG(
llevInfo,
"fix_object: Monster %s has negative speed of %f.\n",
1600 op->name ?
op->name :
"(null)",
op->speed);
1607 &&
op->stats.dam >
op->arch->clone.stats.dam*3)
1608 op->stats.dam =
op->arch->clone.stats.dam*3;
1632 if (
op->move_type == 0)
1653 return op->stats.Dex > 0
1654 &&
op->stats.Str > 0
1655 &&
op->stats.Con > 0
1656 &&
op->stats.Int > 0
1657 &&
op->stats.Wis > 0
1658 &&
op->stats.Pow > 0
1659 &&
op->stats.Cha > 0;
1691 && (atnr == -1 || abil->
resist[i] > abil->
resist[atnr])) {
1706 if (
pl->contr != NULL) {
1720 object *abil = NULL;
1721 object *skin = NULL;
1747 "Your metabolism now focuses on %s!",
1785 LOG(
llevError,
"add_player_exp: couldn't find skill %s\n", skill_name);
1795 skill_obj->
level = 1;
1842 if (
op->level > 1) {
1844 snprintf(
buf,
sizeof(
buf),
"You are now level %d in the %s skill.",
op->level,
op->name);
1846 snprintf(
buf,
sizeof(
buf),
"You are now level %d.",
op->level);
1856 snprintf(
buf,
sizeof(
buf),
"You are now level %d in the %s skill.",
op->level,
op->name);
1858 snprintf(
buf,
sizeof(
buf),
"You are now level %d.",
op->level);
1904 if (
op->total_exp <
op->stats.exp)
1905 op->total_exp =
op->stats.exp;
1908 if (
op->total_exp < 0)
1923 if (
op->contr->last_skill_ob[i] != NULL) {
1927 LOG(
llevDebug,
"pruning removed object from last_skill_ob\n");
1928 op->contr->last_skill_ob[i] = NULL;
1932 if (
op->contr->last_skill_ob[i]->skill != NULL) {
1933 if (!strcmp(
op->contr->last_skill_ob[i]->skill,
name)) {
1934 return op->contr->last_skill_ob[i];
1938 "%s's skill object %s does not have a skill name\n",
1939 op->name,
op->contr->last_skill_ob[i]->name);
1961 object *skill_obj = NULL;
1962 int64_t limit, exp_to_add;
1963 int64_t added_skill_exp = 0, added_skill_total_exp = 0;
1966 if (
op->contr->braced)
1975 if (
op->chosen_skill
1976 &&
op->chosen_skill->type ==
SKILL
1977 && !strcmp(skill_name,
op->chosen_skill->skill))
1978 skill_obj =
op->chosen_skill;
2009 if (exp_to_add > limit)
2025 if (exp_to_add > limit)
2027 added_skill_exp = skill_obj->
stats.
exp;
2029 added_skill_exp = skill_obj->
stats.
exp - added_skill_exp;
2031 added_skill_total_exp = skill_obj->
total_exp;
2033 added_skill_total_exp = skill_obj->
total_exp - added_skill_total_exp;
2039 added_skill_exp = added_skill_total_exp = exp_to_add;
2042 ADD_EXP(
op->stats.exp, (
float)added_skill_exp*(skill_obj ? skill_obj->
expmul : 1));
2069 if (exp >
op->stats.exp)
2070 exp =
op->stats.exp;
2121 float fraction = (float)exp/(
float)
op->stats.exp;
2128 tmp->stats.exp -= del_exp;
2135 tmp->stats.exp -= del_exp;
2142 op->stats.exp -= del_exp;
2168 void change_exp(
object *
op, int64_t exp,
const char *skill_name,
int flag) {
2171 LOG(
llevError,
"change_exp() called for null object!\n");
2201 op->stats.exp += exp;
2235 int64_t percentage_loss;
2253 tmp->stats.exp -= loss;
2264 op->stats.exp -= loss;
2312 void share_exp(
object *
op, int64_t exp,
const char *skill,
int flag) {
2313 int shares = 0,
count = 0;
2317 if (
op->type !=
PLAYER ||
op->contr->party == NULL) {
2322 party =
op->contr->party;
2333 if (
count == 1 || shares > exp)
2336 int64_t share = exp/shares, given = 0, nexp;
2417 index = (size_t)stat;
2441 int on_stat = 0, tmp_bonus;
2457 if (
buf[0] ==
'}') {
2459 LOG(
llevError,
"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2472 while (!isdigit(*cp) && *cp!=
'.' && *cp!=
'-' && *cp!=
'+' && *cp != 0)
2475 if (*cp == 0)
break;
2477 tmp_bonus = atoi(cp);
2480 LOG(
llevError,
"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2484 (*bonuses)[on_stat] = tmp_bonus;
2488 while ((isdigit(*cp) || *cp==
'-' || *cp==
'+') && *cp != 0)
2493 LOG(
llevError,
"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2534 if (
buf[0] ==
'}') {
2536 LOG(
llevError,
"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2549 while (!isdigit(*cp) && *cp!=
'.' && *cp!=
'-' && *cp!=
'+' && *cp != 0)
2552 if (*cp == 0)
break;
2554 tmp_bonus = atof(cp);
2557 LOG(
llevError,
"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2561 (*bonuses)[on_stat] = tmp_bonus;
2567 while ((isdigit(*cp) || *cp==
'-' || *cp==
'+' || *cp==
'.') && *cp != 0)
2572 LOG(
llevError,
"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2606 if ((fp = fopen(
buf,
"r")) == NULL) {
2607 LOG(
llevError,
"Fatal error: could not open experience table (%s)\n",
buf);
2616 if ((cp = strrchr(
buf,
'\n')) != NULL)
2625 while (isspace(*cp) && *cp != 0)
2628 if (!strncasecmp(cp,
"max_stat", 8)) {
2629 int newmax = atoi(cp+8);
2640 LOG(
llevError,
"Got invalid max_stat (%d) from stat_bonus file\n", newmax);
2652 LOG(
llevError,
"Got bonus line or otherwise unknown value before max stat! (%s)\n",
2693 if (!new_int_bonuses[i]) {
2700 if (!new_float_bonuses[i]) {
2730 new_int_bonuses[i] = NULL;
2736 new_float_bonuses[i] = NULL;