--- deliantra/server/common/living.C 2007/11/08 01:14:12 1.79 +++ deliantra/server/common/living.C 2009/11/29 17:41:07 1.105 @@ -1,28 +1,28 @@ /* - * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. + * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team + * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team * Copyright (©) 1992,2007 Frank Tore Johansen * - * Crossfire TRT is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Deliantra is free software: you can redistribute it and/or modify it under + * the terms of the Affero GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the Affero GNU General Public License + * and the GNU General Public License along with this program. If not, see + * . * - * The authors can be reached via e-mail to + * The authors can be reached via e-mail to */ #include -#include /* Handy little macro that adds exp and keeps it within bounds. Since * we are now using 64 bit values, I'm not all concerned about overflow issues @@ -282,21 +282,24 @@ int change_abil (object *op, object *tmp) { - int flag = QUERY_FLAG (tmp, FLAG_APPLIED) ? 1 : -1, success = 0; + int flag = tmp->flag [FLAG_APPLIED] ? 1 : -1; + int success = 0; char message[MAX_BUF]; int potion_max = 0; - /* remember what object was like before it was changed. note that - * refop is a local copy of op only to be used for detecting changes - * found by update_stats. refop is not a real object - */ - object_copy refop = *op; + // keep some stats for comparison purposes + object::flags_t prev_flag = op->flag; + MoveType prev_move_type = op->move_type; + sint16 prev_resist [NROFATTACKS]; // clumsy + assert (sizeof (prev_resist) == sizeof (op->resist)); + memcpy (prev_resist, op->resist, sizeof (prev_resist)); if (op->type == PLAYER) { if (tmp->type == POTION) { potion_max = 1; + for (int j = 0; j < NUM_STATS; j++) { int ostat = op->contr->orig_stats.stat (j); @@ -305,8 +308,7 @@ /* nstat is what the stat will be after use of the potion */ int nstat = flag * i + ostat; - /* Do some bounds checking. While I don't think any - * potions do so right now, there is the potential for potions + /* Do some bounds checking. There is the potential for potions * that adjust that stat by more than one point, so we need * to allow for that. */ @@ -368,19 +370,19 @@ DIFF_MSG (flag, "Your hands begin to glow red.", "Your hands stop glowing red."); } - if (QUERY_FLAG (op, FLAG_LIFESAVE) != QUERY_FLAG (&refop, FLAG_LIFESAVE)) + if (op->flag [FLAG_LIFESAVE] != prev_flag [FLAG_LIFESAVE]) { success = 1; DIFF_MSG (flag, "You feel very protected.", "You don't feel protected anymore."); } - if (QUERY_FLAG (op, FLAG_REFL_MISSILE) != QUERY_FLAG (&refop, FLAG_REFL_MISSILE)) + if (op->flag [FLAG_REFL_MISSILE] != prev_flag [FLAG_REFL_MISSILE]) { success = 1; DIFF_MSG (flag, "A magic force shimmers around you.", "The magic force fades away."); } - if (QUERY_FLAG (op, FLAG_REFL_SPELL) != QUERY_FLAG (&refop, FLAG_REFL_SPELL)) + if (op->flag [FLAG_REFL_SPELL] != prev_flag [FLAG_REFL_SPELL]) { success = 1; DIFF_MSG (flag, "You feel more safe now, somehow.", "Suddenly you feel less safe, somehow."); @@ -392,7 +394,7 @@ * can be misleading (a little higher could be miscontrued from * from fly high) */ - if (tmp->move_type && op->move_type != refop.move_type) + if (tmp->move_type && op->move_type != prev_move_type) { success = 1; @@ -401,7 +403,7 @@ */ if (tmp->move_type & MOVE_FLY_LOW && !(op->move_type & MOVE_FLY_HIGH)) { - DIFF_MSG (flag, "You start to float in the air!.", "You float down to the ground."); + DIFF_MSG (flag, "You start to float in the air!", "You float down to the ground."); } if (tmp->move_type & MOVE_FLY_HIGH) @@ -423,8 +425,8 @@ /* becoming UNDEAD... a special treatment for this flag. Only those not * originally undead may change their status */ - if (!QUERY_FLAG (op->arch, FLAG_UNDEAD)) - if (QUERY_FLAG (op, FLAG_UNDEAD) != QUERY_FLAG (&refop, FLAG_UNDEAD)) + if (!op->arch->flag [FLAG_UNDEAD]) + if (op->flag [FLAG_UNDEAD] != prev_flag [FLAG_UNDEAD]) { success = 1; if (flag > 0) @@ -439,13 +441,13 @@ } } - if (QUERY_FLAG (op, FLAG_STEALTH) != QUERY_FLAG (&refop, FLAG_STEALTH)) + if (op->flag [FLAG_STEALTH] != prev_flag [FLAG_STEALTH]) { success = 1; DIFF_MSG (flag, "You walk more quietly.", "You walk more noisily."); } - if (QUERY_FLAG (op, FLAG_MAKE_INVIS) != QUERY_FLAG (&refop, FLAG_MAKE_INVIS)) + if (op->flag [FLAG_MAKE_INVIS] != prev_flag [FLAG_MAKE_INVIS]) { success = 1; DIFF_MSG (flag, "You become transparent.", "You can see yourself."); @@ -454,12 +456,12 @@ /* blinded you can tell if more blinded since blinded player has minimal * vision */ - if (QUERY_FLAG (tmp, FLAG_BLIND)) + if (tmp->flag [FLAG_BLIND]) { success = 1; if (flag > 0) { - if (QUERY_FLAG (op, FLAG_WIZ)) + if (op->flag [FLAG_WIZ]) new_draw_info (NDI_UNIQUE, 0, op, "Your mortal self is blinded."); else { @@ -471,7 +473,7 @@ } else { - if (QUERY_FLAG (op, FLAG_WIZ)) + if (op->flag [FLAG_WIZ]) new_draw_info (NDI_UNIQUE, 0, op, "Your mortal self can now see again."); else { @@ -483,7 +485,7 @@ } } - if (QUERY_FLAG (op, FLAG_SEE_IN_DARK) != QUERY_FLAG (&refop, FLAG_SEE_IN_DARK)) + if (op->flag [FLAG_SEE_IN_DARK] != prev_flag [FLAG_SEE_IN_DARK]) { success = 1; if (op->type == PLAYER) @@ -491,12 +493,12 @@ DIFF_MSG (flag, "Your vision is better in the dark.", "You see less well in the dark."); } - if (QUERY_FLAG (op, FLAG_XRAYS) != QUERY_FLAG (&refop, FLAG_XRAYS)) + if (op->flag [FLAG_XRAYS] != prev_flag [FLAG_XRAYS]) { success = 1; if (flag > 0) { - if (QUERY_FLAG (op, FLAG_WIZ)) + if (op->flag [FLAG_WIZ]) new_draw_info (NDI_UNIQUE, 0, op, "Your vision becomes a little clearer."); else { @@ -507,7 +509,7 @@ } else { - if (QUERY_FLAG (op, FLAG_WIZ)) + if (op->flag [FLAG_WIZ]) new_draw_info (NDI_UNIQUE, 0, op, "Your vision becomes a bit out of focus."); else { @@ -555,29 +557,26 @@ if (i == ATNR_PHYSICAL) continue; /* Don't display about armour */ - if (op->resist[i] != refop.resist[i]) + if (op->resist [i] != prev_resist [i]) { success = 1; - if (op->resist[i] > refop.resist[i]) - sprintf (message, "Your resistance to %s rises to %d%%.", change_resist_msg[i], op->resist[i]); + + if (op->resist [i] > prev_resist [i]) + sprintf (message, "Your resistance to %s rises to %d%%.", change_resist_msg [i], op->resist [i]); else - sprintf (message, "Your resistance to %s drops to %d%%.", change_resist_msg[i], op->resist[i]); + sprintf (message, "Your resistance to %s drops to %d%%.", change_resist_msg [i], op->resist [i]); new_draw_info (NDI_UNIQUE | NDI_BLUE, 0, op, message); } } if (!potion_max) - { - for (int j = 0; j < NUM_STATS; j++) + for (int j = 0; j < NUM_STATS; j++) + if (int i = tmp->stats.stat (j)) { - if (int i = tmp->stats.stat (j)) - { - success = 1; - DIFF_MSG (i * flag, gain_msg[j], lose_msg[j]); - } + success = 1; + DIFF_MSG (i * flag, gain_msg[j], lose_msg[j]); } - } return success; } @@ -598,7 +597,7 @@ object *tmp; archetype *at; - at = archetype::find (ARCH_DEPLETION); + at = archetype::find (shstr_depletion); if (!at) { LOG (llevError, "Couldn't find archetype depletion.\n"); @@ -610,7 +609,7 @@ if (!tmp) { - tmp = arch_to_object (at); + tmp = at->instance (); tmp = insert_ob_in_ob (tmp, this); SET_FLAG (tmp, FLAG_APPLIED); } @@ -628,7 +627,7 @@ void object::change_luck (int value) { - archetype *at = archetype::find ("luck"); + archetype *at = archetype::find (shstr_luck); if (!at) LOG (llevError, "Couldn't find archetype luck.\n"); else @@ -640,7 +639,7 @@ if (!value) return; - tmp = arch_to_object (at); + tmp = at->instance (); tmp = insert_ob_in_ob (tmp, this); SET_FLAG (tmp, FLAG_APPLIED); } @@ -770,6 +769,8 @@ /* First task is to clear all the values back to their original values */ if (type == PLAYER) { + contr->delayed_update = false; + for (int i = 0; i < NUM_STATS; i++) stat_sum [i] = contr->orig_stats.stat (i); @@ -862,11 +863,7 @@ if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type == POTION) continue; - /* See note in map.c:update_position about making this additive - * since light sources are never applied, need to put check here. - */ - if (tmp->glow_radius > glow_radius) - glow_radius = tmp->glow_radius; + glow_radius += tmp->glow_radius; /* For some things, we don't care what is equipped */ if (tmp->type == SKILL) @@ -889,7 +886,7 @@ } } - /* Container objects are not meant to adjust a players, but other applied + /* Container objects are not meant to adjust players, but other applied * objects need to make adjustments. * This block should handle all player specific changes * The check for Praying is a bit of a hack - god given bonuses are put @@ -916,13 +913,14 @@ continue; for (int i = 0; i < NUM_STATS; i++) - stat_sum [i] = stat_sum [i] + tmp->stats.stat (i); + stat_sum [i] += tmp->stats.stat (i); if (digest_types [tmp->type]) { contr->digestion += tmp->stats.food; contr->gen_hp += tmp->stats.hp; - contr->gen_sp += tmp->stats.sp; + if (tmp->type != BOW) // ugly exception for bows + contr->gen_sp += tmp->stats.sp; contr->gen_grace += tmp->stats.grace; contr->gen_sp_armour += tmp->gen_sp_armour; } @@ -942,7 +940,7 @@ speed_reduce_from_disease = min (speed_reduce_from_disease, tmp->last_sp ? tmp->last_sp / 100.f : 1.f); - /* Pos. and neg. protections are counted seperate (-> pro/vuln). + /* Pos. and neg. protections are counted separate (-> pro/vuln). * (Negative protections are calculated exactly like positive.) * Resistance from potions are treated special as well. If there's * more than one potion-effect, the bigger prot.-value is taken. @@ -1141,10 +1139,10 @@ } if (tmp->stats.wc) - wc -= (tmp->stats.wc + tmp->magic); + wc -= tmp->stats.wc + tmp->magic; if (tmp->stats.ac) - ac -= (tmp->stats.ac + tmp->magic); + ac -= tmp->stats.ac + tmp->magic; if (ARMOUR_SPEED (tmp)) max_speed = min (max_speed, ARMOUR_SPEED (tmp) / 10.f); @@ -1154,6 +1152,8 @@ } /* item is equipped */ } /* for loop of items */ + glow_radius = min (glow_radius, MAX_LIGHT_RADIUS); + /* We've gone through all the objects the player has equipped. For many things, we * have generated intermediate values which we now need to assign. */ @@ -1176,18 +1176,16 @@ { // clamp various player stats for (int i = 0; i < NUM_STATS; ++i) - stats.stat (i) = clamp (stat_sum [i], MIN_STAT, MAX_STAT); + stats.stat (i) = stat_sum [i]; + + check_stat_bounds (&stats); contr->digestion = clamp (contr->digestion, MIN_DIGESTION, MAX_DIGESTION); /* Figure out the players sp/mana/hp totals. */ int pl_level; - check_stat_bounds (&(stats)); - pl_level = level; - - if (pl_level < 1) - pl_level = 1; /* safety, we should always get 1 levels worth of hp! */ + pl_level = max (1, level); /* safety, we should always get 1 levels worth of hp! */ /* You basically get half a con bonus/level. But we do take into account rounding, * so if your bonus is 7, you still get 7 worth of bonus every 2 levels. @@ -1332,9 +1330,6 @@ if (settings.search_items && contr->search_str[0]) speed -= 1; - - if (attacktype == 0) - attacktype = arch->attacktype; } /* End if player */ if (added_speed >= 0) @@ -1363,8 +1358,7 @@ /* Put a lower limit on speed. Note with this speed, you move once every * 25 ticks or so. This amounts to once every 3 seconds of realtime. */ - if (speed < 0.04f && type == PLAYER) - speed = 0.04f; + max_it (speed, is_player () ? MIN_PLAYER_SPEED : MIN_ACTIVE_SPEED); if (speed != old_speed) set_speed (speed); @@ -1412,17 +1406,30 @@ /* It is quite possible that a player's spell costing might have changed, * so we will check that now. */ - if (type == PLAYER) - { - esrv_update_stats (contr); - esrv_update_spells (contr); - } + if (is_player ()) + contr->update_spells (); // update the mapspace, if we are on a map if (!flag [FLAG_REMOVED] && map) map->at (x, y).flags_ = 0; } +void +object::set_glow_radius (sint8 rad) +{ + glow_radius = rad; + + if (is_on_map ()) + update_all_los (map, x, y); + else if (object *env = outer_env ()) + { + env->update_stats (); + + if (env->is_on_map ()) + update_all_los (env->map, env->x, env->y); + } +} + /* * Returns true if the given player is a legal class. * The function to add and remove class-bonuses to the stats doesn't @@ -1446,11 +1453,6 @@ * set the new dragon name after gaining levels or * changing ability focus (later this can be extended to * eventually change the player's face and animation) - * - * Note that the title is written to 'own_title' in the - * player struct. This should be changed to 'ext_title' - * as soon as clients support this! - * Please, anyone, write support for 'ext_title'. */ void set_dragon_name (object *pl, const object *abil, const object *skin) @@ -1478,29 +1480,17 @@ if (atnr_is_dragon_enabled (abil->stats.exp) && abil->resist[abil->stats.exp] >= level) atnr = abil->stats.exp; - level = (int) (level / 5.); - /* now set the new title */ - if (pl->contr) + if (level < 25) sprintf (pl->contr->title, "%s hatchling", attacks[atnr]); + else if (level < 50) sprintf (pl->contr->title, "%s wyrm" , attacks[atnr]); + else if (level < 75) sprintf (pl->contr->title, "%s wyvern" , attacks[atnr]); + else if (level < 100) sprintf (pl->contr->title, "%s dragon" , attacks[atnr]); + else { - if (level == 0) - sprintf (pl->contr->title, "%s hatchling", attacks[atnr]); - else if (level == 1) - sprintf (pl->contr->title, "%s wyrm", attacks[atnr]); - else if (level == 2) - sprintf (pl->contr->title, "%s wyvern", attacks[atnr]); - else if (level == 3) - sprintf (pl->contr->title, "%s dragon", attacks[atnr]); - else - { - /* special titles for extra high resistance! */ - if (skin->resist[atnr] > 80) - sprintf (pl->contr->title, "legendary %s dragon", attacks[atnr]); - else if (skin->resist[atnr] > 50) - sprintf (pl->contr->title, "ancient %s dragon", attacks[atnr]); - else - sprintf (pl->contr->title, "big %s dragon", attacks[atnr]); - } + /* special titles for extra high resistance! */ + if (skin->resist[atnr] > 80) sprintf (pl->contr->title, "legendary %s dragon", attacks[atnr]); + else if (skin->resist[atnr] > 50) sprintf (pl->contr->title, "ancient %s dragon" , attacks[atnr]); + else sprintf (pl->contr->title, "big %s dragon" , attacks[atnr]); } strcpy (pl->contr->own_title, ""); @@ -1511,7 +1501,7 @@ * an overall level. Here, the dragon might gain new abilities * or change the ability-focus. */ -void +static void dragon_level_gain (object *who) { object *abil = NULL; /* pointer to dragon ability force */ @@ -1577,7 +1567,7 @@ skill_obj = get_archetype_by_skill_name (skill_name, SKILL); if (!skill_obj) { - LOG (llevError, "add_player_exp: couldn't find skill %s\n", skill_name); + LOG (llevError, "give_skill_by_name: couldn't find skill %s\n", skill_name); return NULL; } @@ -1587,14 +1577,10 @@ CLEAR_FLAG (skill_obj, FLAG_CAN_USE_SKILL); skill_obj->stats.exp = 0; skill_obj->level = 1; - insert_ob_in_ob (skill_obj, op); + op->insert (skill_obj); if (player *pl = op->contr) - { - pl->last_skill_ob [skill_obj->subtype] = skill_obj; - if (pl->ns) - pl->ns->last_skill_exp[skill_obj->subtype] = -1;//TODO: should be made superfluous - } + pl->link_skills (); return skill_obj; } @@ -1664,12 +1650,7 @@ } if (changed) - { - who->update_stats (); - esrv_update_stats (who->contr); - /* check if the spell data has changed */ - esrv_update_spells (who->contr); - } + who->update_stats (); // should cause esrv_update_stats and esrv_update_spells } /* @@ -1723,7 +1704,7 @@ static void add_player_exp (object *op, sint64 exp, const char *skill_name, int flag) { - object *skill_obj = NULL; + object *skill_obj; sint64 limit, exp_to_add; int i; @@ -1736,29 +1717,22 @@ * chosen_skill. This means we don't need to search through * the players inventory. */ + skill_obj = 0; + if (skill_name) { - if (op->chosen_skill && op->chosen_skill->type == SKILL && !strcmp (skill_name, op->chosen_skill->skill)) - skill_obj = op->chosen_skill; - else + skill_obj = op->contr->find_skill (skill_name); + + /* Player doesn't have the skill. Check to see what to do, and give + * it to the player if necessary + */ + if (!skill_obj) { - for (i = 0; i < NUM_SKILLS; i++) - if (op->contr->last_skill_ob[i] && !strcmp (op->contr->last_skill_ob[i]->skill, skill_name)) - { - skill_obj = op->contr->last_skill_ob[i]; - break; - } + if (flag == SK_EXP_NONE) + return; - /* Player doesn't have the skill. Check to see what to do, and give - * it to the player if necessary - */ - if (!skill_obj) - { - if (flag == SK_EXP_NONE) - return; - else if (flag == SK_EXP_ADD_SKILL) - give_skill_by_name (op, skill_name); - } + if (flag == SK_EXP_ADD_SKILL) + skill_obj = give_skill_by_name (op, skill_name); } } @@ -1801,28 +1775,32 @@ } /* This function checks to make sure that object 'op' can - * lost 'exp' experience. It returns the amount of exp + * lose 'exp' experience. It returns the amount of exp * object 'op' can in fact lose - it basically makes * adjustments based on permanent exp and the like. * This function should always be used for losing experience - * the 'exp' value passed should be positive - this is the * amount that should get subtract from the player. */ -sint64 +static sint64 check_exp_loss (const object *op, sint64 exp) { sint64 del_exp; if (exp > op->stats.exp) exp = op->stats.exp; + if (settings.permanent_exp_ratio) { del_exp = (sint64) ((op->stats.exp - op->perm_exp) * PERM_EXP_MAX_LOSS_RATIO); + if (del_exp < 0) del_exp = 0; + if (exp > del_exp) exp = del_exp; } + return exp; } @@ -1832,10 +1810,9 @@ if (exp < 0) return check_exp_loss (op, exp); else - return MIN (exp, (sint64) MAX_EXPERIENCE - op->stats.exp); + return min (exp, (sint64)MAX_EXPERIENCE - op->stats.exp); } - /* Subtracts experience from player. * if skill is set and flag == SK_SUBTRACT_SKILL_EXP, then we * only subtract from the matching skill. Otherwise, @@ -1858,7 +1835,7 @@ for (tmp = op->inv; tmp; tmp = tmp->below) if (tmp->type == SKILL && tmp->stats.exp) { - if (flag == SK_SUBTRACT_SKILL_EXP && skill && !strcmp (tmp->skill, skill)) + if (flag == SK_SUBTRACT_SKILL_EXP && skill && !strcmp (&tmp->skill, skill)) { del_exp = check_exp_loss (tmp, exp); tmp->stats.exp -= del_exp; @@ -1956,17 +1933,15 @@ void apply_death_exp_penalty (object *op) { - object *tmp; sint64 loss; sint64 percentage_loss; /* defined by the setting 'death_penalty_percent' */ sint64 level_loss; /* defined by the setting 'death_penalty_levels */ - for (tmp = op->inv; tmp; tmp = tmp->below) + for (object *tmp = op->inv; tmp; tmp = tmp->below) if (tmp->type == SKILL && tmp->stats.exp) { - percentage_loss = tmp->stats.exp * settings.death_penalty_ratio / 100; - level_loss = tmp->stats.exp - levels[MAX (0, tmp->level - settings.death_penalty_level)]; + level_loss = tmp->stats.exp - levels [max (0, tmp->level - settings.death_penalty_level)]; /* With the revised exp system, you can get cases where * losing several levels would still require that you have more @@ -1976,18 +1951,19 @@ if (level_loss < 0) level_loss = 0; - loss = check_exp_loss (tmp, MIN (level_loss, percentage_loss)); + loss = check_exp_loss (tmp, min (level_loss, percentage_loss)); tmp->stats.exp -= loss; player_lvl_adj (op, tmp); } percentage_loss = op->stats.exp * settings.death_penalty_ratio / 100; - level_loss = op->stats.exp - levels[MAX (0, op->level - settings.death_penalty_level)]; + level_loss = op->stats.exp - levels[max (0, op->level - settings.death_penalty_level)]; if (level_loss < 0) level_loss = 0; - loss = check_exp_loss (op, MIN (level_loss, percentage_loss)); + + loss = check_exp_loss (op, min (level_loss, percentage_loss)); op->stats.exp -= loss; player_lvl_adj (op, NULL);