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) {
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");
554 "You walk more quietly.",
555 "You walk more noisily.");
560 "You become transparent.",
561 "You can see yourself.");
594 "Your vision is better in the dark.",
595 "You see less well in the dark.");
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.");
685 "Your resistance to %s rises to %d%%.",
689 "Your resistance to %s drops to %d%%.",
766 if (level != -1 && level < op->level)
781 return (count == 0) ? 0 : 1;
816 if (new_luck >= -100 && new_luck <= 100) {
894 static void fix_player(
object *op,
int *ac,
int *wc,
const object *grace_obj,
const object *mana_obj,
const object *wc_obj,
int weapon_speed,
float added_speed)
897 float character_load = 0.0, maxhp, tmpf;
903 pl_level = op->
level;
916 for (i = 1, op->
stats.
maxhp = 0; i <= pl_level && i <= 10; i++) {
921 if (tmpf < 1.0) tmpf = 1.0;
942 if (!mana_obj || !mana_obj->
level) {
945 float sp_tmp = 0.0, mana_bonus;
948 mana_lvl_max = (mana_obj->
level >10 ? 10: mana_obj->
level);
951 for (i = 1; i <= mana_lvl_max; i++) {
957 if (i == 1) stmp += mana_bonus;
967 if (mana_obj->
level > 10)
976 if (!grace_obj || !grace_obj->
level) {
984 float sp_tmp = 0.0, grace_bonus;
988 for (i = 1; i <= grace_obj->
level && i <= 10; i++) {
993 grace_tmp += grace_bonus;
1002 if (grace_obj->
level > 10)
1025 if (wc_obj && wc_obj->
level >= 1) {
1027 int wc_increase_rate;
1029 wc_increase_rate = wc_in?atoi(wc_in):5;
1030 assert(wc_increase_rate != 0);
1033 (*wc) -= (wc_obj->
level-1)/wc_increase_rate;
1066 if (character_load >= 1.0)
1067 character_load = 1.0;
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;
1126 const object *grace_obj = NULL, *mana_obj = NULL, *wc_obj = NULL;
1193 prot[i] = op->
resist[i], vuln[i] = 0;
1195 vuln[i] = -(op->
resist[i]), prot[i] = 0;
1196 potion_resist[i] = 0;
1237 if (tmp->type ==
SKILL) {
1242 else if (tmp->level > mana_obj->level)
1248 else if (tmp->level > grace_obj->
level)
1265 if (tmp->type ==
BOW)
1268 if (tmp->type ==
WAND || tmp->type ==
ROD)
1331 if (tmp->type ==
SYMPTOM && tmp->last_sp) {
1333 if (((
float)tmp->last_sp/100.0) < speed_reduce_from_disease)
1334 speed_reduce_from_disease = (float)tmp->last_sp/100.0;
1342 if (tmp->type !=
POTION) {
1348 if (potion_resist[i])
1349 potion_resist[i] =
MAX(potion_resist[i], tmp->resist[i]);
1351 potion_resist[i] = tmp->resist[i];
1352 }
else if (tmp->resist[i] > 0)
1353 prot[i] += ((100-prot[i])*tmp->resist[i])/100;
1354 else if (tmp->resist[i] < 0)
1355 vuln[i] += ((100-vuln[i])*(-tmp->resist[i]))/100;
1360 if (tmp->type !=
BOW && tmp->type !=
SYMPTOM)
1398 if (tmp->stats.exp && tmp->type !=
SKILL) {
1399 added_speed += (float)tmp->stats.exp/3.0;
1402 switch (tmp->type) {
1413 LOG(
llevDebug,
"fix_object, op %s has multiple skills applied\n", op->
name);
1416 if (tmp->stats.dam > 0) {
1419 if (weapon_speed < 0)
1425 wc -= (tmp->stats.wc+tmp->magic);
1427 if (tmp->slaying != NULL) {
1434 ac -= (tmp->stats.ac+tmp->magic);
1443 LOG(
llevDebug,
"fix_object, op %s has multiple skills applied\n", op->
name);
1462 wc -= tmp->stats.wc;
1464 op->
stats.
dam += (tmp->stats.dam+tmp->magic);
1466 ac -= (tmp->stats.ac+tmp->magic);
1470 wc -= tmp->stats.wc;
1471 if (tmp->stats.ac && tmp->stats.ac+tmp->magic > 0)
1472 ac -= tmp->stats.ac+tmp->magic;
1473 op->
stats.
dam += (tmp->stats.dam+tmp->magic);
1474 weapon_speed = ((int)
WEAPON_SPEED(tmp)*2-tmp->magic)/2;
1475 if (weapon_speed < 0)
1477 if (tmp->slaying != NULL) {
1501 if (tmp->stats.wc) {
1508 wc -= tmp->stats.wc;
1510 else if (best_wc < tmp->stats.wc) {
1512 best_wc = tmp->stats.wc;
1513 wc -= tmp->stats.wc;
1516 if (tmp->stats.ac) {
1528 ac -= tmp->stats.ac+tmp->magic;
1530 else if (best_ac < tmp->stats.ac+tmp->magic) {
1532 best_ac = tmp->stats.ac+tmp->magic;
1533 ac -= (tmp->stats.ac+tmp->magic);
1536 if (tmp->stats.dam && tmp->type ==
BRACERS)
1537 op->
stats.
dam += (tmp->stats.dam+tmp->magic);
1556 op->
resist[i] = prot[i]-vuln[i];
1557 if (potion_resist[i]
1558 && ((potion_resist[i] > op->
resist[i]) || (potion_resist[i] < 0)))
1559 op->
resist[i] = potion_resist[i];
1562 fix_player(op, &ac, &wc, grace_obj, mana_obj, wc_obj, weapon_speed, added_speed);
1564 op->
speed = op->
speed*speed_reduce_from_disease;
1567 if (op->
speed > max)
1570 op->
speed += added_speed/10.0;
1592 if (added_speed >= 0)
1593 LOG(
llevInfo,
"fix_object: Monster %s has negative speed of %f.\n",
1685 && (atnr == -1 || abil->
resist[i] > abil->
resist[atnr])) {
1697 level = (int)(level/5.);
1700 if (pl->
contr != NULL) {
1714 object *abil = NULL;
1715 object *skin = NULL;
1741 "Your metabolism now focuses on %s!",
1779 LOG(
llevError,
"add_player_exp: couldn't find skill %s\n", skill_name);
1789 skill_obj->
level = 1;
1836 if (op->
level > 1) {
1838 snprintf(buf,
sizeof(buf),
"You are now level %d in the %s skill.", op->
level, op->
name);
1840 snprintf(buf,
sizeof(buf),
"You are now level %d.", op->
level);
1850 snprintf(buf,
sizeof(buf),
"You are now level %d in the %s skill.", op->
level, op->
name);
1852 snprintf(buf,
sizeof(buf),
"You are now level %d.", op->
level);
1871 return expmul*levels[level];
1921 LOG(
llevDebug,
"pruning removed object from last_skill_ob\n");
1932 "%s's skill object %s does not have a skill name\n",
1955 object *skill_obj = NULL;
1957 int64_t added_skill_exp, added_skill_total_exp;
2003 if (exp_to_add > limit)
2019 if (exp_to_add > limit)
2021 added_skill_exp = skill_obj->
stats.
exp;
2023 added_skill_exp = skill_obj->
stats.
exp - added_skill_exp;
2025 added_skill_total_exp = skill_obj->
total_exp;
2027 added_skill_total_exp = skill_obj->
total_exp - added_skill_total_exp;
2033 added_skill_exp = added_skill_total_exp = exp_to_add;
2115 float fraction = (float)exp/(
float)op->
stats.
exp;
2119 if (tmp->type ==
SKILL && tmp->stats.exp) {
2122 tmp->stats.exp -= del_exp;
2129 tmp->stats.exp -= del_exp;
2165 LOG(
llevError,
"change_exp() called for null object!\n");
2233 if (tmp->type ==
SKILL && tmp->stats.exp) {
2247 tmp->stats.exp -= loss;
2307 int shares = 0, count = 0;
2327 if (count == 1 || shares > exp)
2330 int64_t share = exp/shares, given = 0, nexp;
2333 nexp = (pl->
ob->
level+4)*share;
2411 index = (size_t)stat;
2412 return MIN(index, max_index);
2435 int on_stat = 0, tmp_bonus;
2439 while (fgets(buf,
MAX_BUF-1, fp) != NULL) {
2451 if (buf[0] ==
'}') {
2453 LOG(
llevError,
"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2466 while (!isdigit(*cp) && *cp!=
'.' && *cp!=
'-' && *cp!=
'+' && *cp != 0)
2469 if (*cp == 0)
break;
2471 tmp_bonus = atoi(cp);
2474 LOG(
llevError,
"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2478 (*bonuses)[on_stat] = tmp_bonus;
2482 while ((isdigit(*cp) || *cp==
'-' || *cp==
'+') && *cp != 0)
2487 LOG(
llevError,
"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2516 while (fgets(buf,
MAX_BUF-1, fp) != NULL) {
2528 if (buf[0] ==
'}') {
2530 LOG(
llevError,
"Number of bonus does not match max stat (%d!=%d, bonus=%s)\n",
2543 while (!isdigit(*cp) && *cp!=
'.' && *cp!=
'-' && *cp!=
'+' && *cp != 0)
2546 if (*cp == 0)
break;
2548 tmp_bonus = atof(cp);
2551 LOG(
llevError,
"Number of bonus entries exceed max stat (line=%s, bonus=%s)\n",
2555 (*bonuses)[on_stat] = tmp_bonus;
2561 while ((isdigit(*cp) || *cp==
'-' || *cp==
'+' || *cp==
'.') && *cp != 0)
2566 LOG(
llevError,
"Reached end of file without getting close brace? bonus=%s\n", bonus_name);
2600 if ((fp = fopen(buf,
"r")) == NULL) {
2601 LOG(
llevError,
"Fatal error: could not open experience table (%s)\n", buf);
2605 while (fgets(buf,
MAX_BUF-1, fp) != NULL) {
2610 if ((cp = strrchr(buf,
'\n')) != NULL)
2619 while (isspace(*cp) && *cp != 0)
2623 int newmax = atoi(cp+8);
2634 LOG(
llevError,
"Got invalid max_stat (%d) from stat_bonus file\n", newmax);
2646 LOG(
llevError,
"Got bonus line or otherwise unknown value before max stat! (%s)\n",
2666 if (i == NUM_INT_BONUSES) {
2674 if (i == NUM_FLOAT_BONUSES) {
2675 LOG(
llevError,
"Unknown line in stat_bonus file: %s\n", buf);
2687 if (!new_int_bonuses[i]) {
2694 if (!new_float_bonuses[i]) {
2706 LOG(
llevError,
"Got error reading stat_bonus: %s\n", buf);
2724 new_int_bonuses[i] = NULL;
2730 new_float_bonuses[i] = NULL;
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
static float get_con_bonus(int stat)
void set_attr_value(living *stats, int attr, int8_t value)
#define NUM_BODY_LOCATIONS
archetype * find_archetype(const char *name)
#define WEAPON_SPEED(xyz)
int64_t check_exp_adjust(const object *op, int64_t exp)
void drain_stat(object *op)
object * find_applied_skill_by_name(const object *op, const char *name)
int64_t level_exp(int level, double expmul)
const char *const restore_msg[NUM_STATS]
uint8_t spell_encumbrance
sstring add_refcount(sstring str)
static float get_grace_bonus(int stat)
void link_player_skills(object *op)
int get_dam_bonus(int stat)
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_LOSS
uint8_t death_penalty_level
#define ADD_EXP(exptotal, exp)
int exp_level(int64_t exp)
#define PERM_EXP_MAX_LOSS_RATIO
void free_string(sstring str)
const char * object_get_value(const object *op, const char *const key)
#define MSG_TYPE_ATTRIBUTE_ATTACKTYPE_GAIN
int object_check_move_on(object *op, object *originator)
object * ranges[range_size]
void change_luck(object *op, int value)
object * arch_present_in_ob(const archetype *at, const object *op)
int64_t check_exp_loss(const object *op, int64_t exp)
int8_t get_attr_value(const living *stats, int attr)
uint8_t death_penalty_ratio
uint32_t get_weight_limit(int stat)
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
const char *const drain_msg[NUM_STATS]
#define ADD_TOTALEXP(exptotal, exp)
#define IS_MANA_SKILL(num)
object * give_skill_by_name(object *op, const char *skill_name)
#define FREE_PLAYER_LOAD_PERCENT
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)
int get_cha_bonus(int stat)
struct obj * chosen_skill
void object_free_drop_inventory(object *ob)
int change_abil(object *op, object *tmp)
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
#define NUM_FLOAT_BONUSES
void player_lvl_adj(object *who, object *op)
#define MSG_TYPE_ATTRIBUTE_MOVE
const char *const gain_msg[NUM_STATS]
static const int savethrow[MAX_SAVE_LEVEL+1]
int get_turn_bonus(int stat)
static int load_table_int(int **bonuses, FILE *fp, char *bonus_name)
object * object_insert_in_ob(object *op, object *where)
#define MSG_TYPE_ATTRIBUTE_PROTECTION_GAIN
static void subtract_player_exp(object *op, int64_t exp, const char *skill, int flag)
#define FLAG_CAN_USE_SKILL
const char *const statname[NUM_STATS]
int is_dragon_pl(const object *op)
void drain_specific_stat(object *op, int deplete_stats)
#define MSG_TYPE_ATTRIBUTE
#define PERM_EXP(exptotal)
int die_roll(int num, int size, const object *op, int goodbad)
void change_attr_value(living *stats, int attr, int8_t value)
archetype * get_archetype_by_skill_name(const char *skill, int type)
int get_fear_bonus(int stat)
#define ARMOUR_SPEED(xyz)
int allowed_class(const object *op)
static float get_sp_bonus(int stat)
struct obj * current_weapon
EXTERN const char *const change_resist_msg[NROFATTACKS]
void add_statbonus(object *op)
#define MSG_TYPE_ATTRIBUTE_LEVEL_GAIN
static const char * float_bonus_names[NUM_FLOAT_BONUSES]
static void dragon_level_gain(object *who)
static float * float_bonuses[NUM_FLOAT_BONUSES]
int on_same_map(const object *op1, const object *op2)
#define QUERY_FLAG(xyz, p)
#define BASE_WEAPON_SPEED
#define CLEAR_FLAG(xyz, p)
static int * int_bonuses[NUM_INT_BONUSES]
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
int strncasecmp(const char *s1, const char *s2, int n)
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
#define FLAG_READY_WEAPON
#define DIFF_MSG(flag, subtype1, subtype2, msg1, msg2)
void calc_perm_exp(object *op)
int16_t resist[NROFATTACKS]
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_START
const char *const lose_msg[NUM_STATS]
uint8_t permanent_exp_ratio
static void add_player_exp(object *op, int64_t exp, const char *skill_name, int flag)
#define INT_CLERIC_CHANCE
int8_t body_info[NUM_BODY_LOCATIONS]
void player_set_dragon_title(struct pl *pl, int level, const char *attack, int skin_resist)
#define MSG_TYPE_ATTRIBUTE_STAT_GAIN
#define MSG_TYPE_ATTRIBUTE_LEVEL_LOSS
void init_stats(int reload)
static size_t get_index(int stat, size_t max_index)
static int load_table_float(float **bonuses, FILE *fp, char *bonus_name)
int remove_depletion(object *op, int level)
void apply_death_exp_penalty(object *op)
sstring add_string(const char *str)
EXTERN player * first_player
int get_cleric_chance(int stat)
void dragon_ability_gain(object *who, int atnr, int level)
void LOG(LogLevel logLevel, const char *format,...)
int get_learn_spell(int stat)
object * last_skill_ob[MAX_SKILLS]
int did_make_save(const object *op, int level, int bonus)
#define MSG_TYPE_ATTRIBUTE_RACE
void set_dragon_name(object *pl, const object *abil, const object *skin)
#define MSG_TYPE_ATTRIBUTE_PROTECTION_LOSS
#define SK_SUBTRACT_SKILL_EXP
void share_exp(object *op, int64_t exp, const char *skill, int flag)
void remove_statbonus(object *op)
void esrv_update_spells(player *pl)
#define IS_COMBAT_SKILL(num)
int random_roll(int min, int max, const object *op, int goodbad)
#define FREE_AND_CLEAR(xyz)
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
const char *const short_stat_name[NUM_STATS]
#define FLAG_REFL_MISSILE
int get_dex_bonus(int stat)
#define FLOAT_GRACE_BONUS
void fix_object(object *op)
#define IS_GRACE_SKILL(num)
float get_speed_bonus(int stat)
static const char * int_bonus_names[NUM_INT_BONUSES]
object * arch_to_object(archetype *at)
void object_update_speed(object *op)
#define FOR_INV_PREPARE(op_, it_)
void object_remove(object *op)
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
const char *const attacks[NROFATTACKS]
int8_t body_used[NUM_BODY_LOCATIONS]
int atnr_is_dragon_enabled(int attacknr)
int get_thaco_bonus(int stat)
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)