--- deliantra/server/common/living.C 2006/09/10 16:00:23 1.9
+++ deliantra/server/common/living.C 2008/09/25 22:58:13 1.90
@@ -1,34 +1,27 @@
-
/*
- * static char *rcsid_living_c =
- * "$Id: living.C,v 1.9 2006/09/10 16:00:23 root Exp $";
+ * This file is part of Deliantra, the Roguelike Realtime MMORPG.
+ *
+ * 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
+ *
+ * Deliantra 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.
+ *
+ * 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 .
+ *
+ * The authors can be reached via e-mail to
*/
-/*
- CrossFire, A Multiplayer game for X-windows
-
- Copyright (C) 2002 Mark Wedel & Crossfire Development Team
- Copyright (C) 1992 Frank Tore Johansen
-
- This program 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- The authors can be reached via e-mail at crossfire-devel@real-time.com
-*/
-
#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
@@ -166,11 +159,7 @@
#define MAX_EXP_IN_OBJ levels[settings.max_level]/(MAX_EXP_CAT - 1)
-#ifndef WIN32
-extern uint64 *levels;
-#else
extern sint64 *levels;
-#endif
#define MAX_SAVE_LEVEL 110
@@ -203,160 +192,68 @@
"You're feeling clumsy!",
"You feel less healthy",
"You suddenly begin to lose your memory!",
- "Your face gets distorted!",
"Watch out, your mind is going!",
- "Your spirit feels drained!"
+ "Your spirit feels drained!",
+ "Your face gets distorted!",
};
const char *const restore_msg[NUM_STATS] = {
"You feel your strength return.",
"You feel your agility return.",
"You feel your health return.",
+ "You feel your memory return.",
"You feel your wisdom return.",
+ "You feel your spirits return.",
"You feel your charisma return.",
- "You feel your memory return.",
- "You feel your spirits return."
};
const char *const gain_msg[NUM_STATS] = {
"You feel stronger.",
"You feel more agile.",
"You feel healthy.",
+ "You feel smarter.",
"You feel wiser.",
+ "You feel more potent.",
"You seem to look better.",
- "You feel smarter.",
- "You feel more potent."
};
const char *const lose_msg[NUM_STATS] = {
"You feel weaker!",
"You feel clumsy!",
"You feel less healthy!",
+ "You feel stupid!",
"You lose some of your memory!",
+ "You feel less potent!",
"You look ugly!",
- "You feel stupid!",
- "You feel less potent!"
};
const char *const statname[NUM_STATS] = {
- "strength", "dexterity", "constitution", "wisdom", "charisma", "intelligence", "power"
+ "strength", "dexterity", "constitution", "intelligence", "wisdom", "power", "charisma"
};
const char *const short_stat_name[NUM_STATS] = {
- "Str", "Dex", "Con", "Wis", "Cha", "Int", "Pow"
+ "Str", "Dex", "Con", "Int", "Wis", "Pow", "Cha"
};
/*
- * sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on
- * what attr is (STR to POW).
- */
-
-void
-set_attr_value (living * stats, int attr, sint8 value)
-{
- switch (attr)
- {
- case STR:
- stats->Str = value;
- break;
- case DEX:
- stats->Dex = value;
- break;
- case CON:
- stats->Con = value;
- break;
- case WIS:
- stats->Wis = value;
- break;
- case POW:
- stats->Pow = value;
- break;
- case CHA:
- stats->Cha = value;
- break;
- case INT:
- stats->Int = value;
- break;
- }
-}
-
-/*
* Like set_attr_value(), but instead the value (which can be negative)
* is added to the specified stat.
*/
-
void
-change_attr_value (living * stats, int attr, sint8 value)
+change_attr_value (living *stats, int attr, sint8 value)
{
- if (value == 0)
- return;
- switch (attr)
- {
- case STR:
- stats->Str += value;
- break;
- case DEX:
- stats->Dex += value;
- break;
- case CON:
- stats->Con += value;
- break;
- case WIS:
- stats->Wis += value;
- break;
- case POW:
- stats->Pow += value;
- break;
- case CHA:
- stats->Cha += value;
- break;
- case INT:
- stats->Int += value;
- break;
- default:
- LOG (llevError, "Invalid attribute in change_attr_value: %d\n", attr);
- }
-}
-
-/*
- * returns the specified stat. See also set_attr_value().
- */
-
-sint8
-get_attr_value (const living * stats, int attr)
-{
- switch (attr)
- {
- case STR:
- return (stats->Str);
- case DEX:
- return (stats->Dex);
- case CON:
- return (stats->Con);
- case WIS:
- return (stats->Wis);
- case CHA:
- return (stats->Cha);
- case INT:
- return (stats->Int);
- case POW:
- return (stats->Pow);
- }
- return 0;
+ stats->stat (attr) += value;
}
/*
* Ensures that all stats (str/dex/con/wis/cha/int) are within the
* 1-30 stat limit.
*/
-
void
-check_stat_bounds (living * stats)
+check_stat_bounds (living *stats)
{
- int i, v;
-
- for (i = 0; i < NUM_STATS; i++)
- if ((v = get_attr_value (stats, i)) > MAX_STAT)
- set_attr_value (stats, i, MAX_STAT);
- else if (v < MIN_STAT)
- set_attr_value (stats, i, MIN_STAT);
+ for (int i = 0; i < NUM_STATS; i++)
+ {
+ sint8 &v = stats->stat (i);
+ v = clamp (v, MIN_STAT, MAX_STAT);
+ }
}
#define ORIG_S(xyz,abc) (op->contr->orig_stats.abc)
@@ -375,7 +272,7 @@
* It is the calling functions responsibilty to check to see if the object
* can be applied or not.
* The main purpose of calling this function is the messages that are
- * displayed - fix_player should really always be called after this when
+ * displayed - update_stats should really always be called after this when
* removing an object - that is because it is impossible to know if some object
* is the only source of an attacktype or spell attunement, so this function
* will clear the bits, but the player may still have some other object
@@ -384,45 +281,44 @@
int
change_abil (object *op, object *tmp)
{
- int flag = QUERY_FLAG (tmp, FLAG_APPLIED) ? 1 : -1, i, j, 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 fix_player. refop is not a real object
- */
- object_pod 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 (j = 0; j < NUM_STATS; j++)
- {
- int nstat, ostat;
- ostat = get_attr_value (&(op->contr->orig_stats), j);
- i = get_attr_value (&(tmp->stats), j);
+ for (int j = 0; j < NUM_STATS; j++)
+ {
+ int ostat = op->contr->orig_stats.stat (j);
+ int i = tmp->stats.stat (j);
/* nstat is what the stat will be after use of the potion */
- nstat = flag * i + ostat;
+ 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.
*/
if (nstat < 1 && i * flag < 0)
nstat = 1;
- else if (nstat > 20 + get_attr_value (&(op->arch->clone.stats), j))
- {
- nstat = 20 + get_attr_value (&(op->arch->clone.stats), j);
- }
+ else if (nstat > 20 + op->arch->stats.stat (j))
+ nstat = 20 + op->arch->stats.stat (j);
+
if (nstat != ostat)
{
- set_attr_value (&(op->contr->orig_stats), j, nstat);
+ op->contr->orig_stats.stat (j) = nstat;
potion_max = 0;
}
else if (i)
@@ -431,38 +327,40 @@
potion_max = 1;
}
}
+
/* This section of code ups the characters normal stats also. I am not
* sure if this is strictly necessary, being that fix_player probably
* recalculates this anyway.
*/
- for (j = 0; j < NUM_STATS; j++)
- change_attr_value (&(op->stats), j, flag * get_attr_value (&(tmp->stats), j));
- check_stat_bounds (&(op->stats));
+ for (int j = 0; j < NUM_STATS; j++)
+ change_attr_value (&op->stats, j, flag * tmp->stats.stat (j));
+
+ check_stat_bounds (&op->stats);
} /* end of potion handling code */
}
- /* reset attributes that fix_player doesn't reset since it doesn't search
+ /* reset attributes that update_stats doesn't reset since it doesn't search
* everything to set
*/
if (flag == -1)
{
- op->attacktype &= ~tmp->attacktype;
- op->path_attuned &= ~tmp->path_attuned;
+ op->attacktype &= ~tmp->attacktype;
+ op->path_attuned &= ~tmp->path_attuned;
op->path_repelled &= ~tmp->path_repelled;
- op->path_denied &= ~tmp->path_denied;
+ op->path_denied &= ~tmp->path_denied;
/* Presuming here that creatures only have move_type,
* and not the other move_ fields.
*/
- op->move_type &= ~tmp->move_type;
+ op->move_type &= ~tmp->move_type;
}
/* call fix_player since op object could have whatever attribute due
- * to multiple items. if fix_player always has to be called after
+ * to multiple items. if update_stats always has to be called after
* change_ability then might as well call it from here
*/
- fix_player (op);
+ op->update_stats ();
- /* Fix player won't add the bows ability to the player, so don't
+ /* update_stats won't add the bows ability to the player, so don't
* print out message if this is a bow.
*/
if (tmp->attacktype & AT_CONFUSION && tmp->type != BOW)
@@ -470,28 +368,32 @@
success = 1;
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.");
}
+
/* movement type has changed. We don't care about cases where
* user has multiple items giving the same type appled like we
* used to - that is more work than what we gain, plus messages
* 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;
@@ -500,7 +402,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)
@@ -508,9 +410,10 @@
/* double conditional - second case covers if you have move_fly_low -
* in that case, you don't actually land
*/
- DIFF_MSG (flag, "You soar into the air air!.",
+ DIFF_MSG (flag, "You soar into the air!",
(op->move_type & MOVE_FLY_LOW ? "You fly lower in the air" : "You float down to the ground."));
}
+
if (tmp->move_type & MOVE_SWIM)
DIFF_MSG (flag, "You feel ready for a swim", "You no longer feel like swimming");
@@ -521,8 +424,8 @@
/* becoming UNDEAD... a special treatment for this flag. Only those not
* originally undead may change their status
*/
- if (!QUERY_FLAG (&op->arch->clone, 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)
@@ -532,30 +435,32 @@
}
else
{
- op->race = op->arch->clone.race;
+ op->race = op->arch->race;
new_draw_info (NDI_UNIQUE, 0, op, "Your lifeforce returns!");
}
}
- 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.");
}
+
/* 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
{
@@ -567,7 +472,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
{
@@ -579,7 +484,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)
@@ -587,12 +492,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
{
@@ -603,7 +508,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
{
@@ -646,34 +551,32 @@
}
/* Messages for changed resistance */
- for (i = 0; i < NROFATTACKS; i++)
+ for (int i = 0; i < NROFATTACKS; i++)
{
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 (tmp->type != EXPERIENCE && !potion_max)
- {
- for (j = 0; j < NUM_STATS; j++)
+ if (!potion_max)
+ for (int j = 0; j < NUM_STATS; j++)
+ if (int i = tmp->stats.stat (j))
{
- if ((i = get_attr_value (&(tmp->stats), j)) != 0)
- {
- 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;
}
@@ -681,20 +584,19 @@
* Stat draining by Vick 930307
* (Feeling evil, I made it work as well now. -Frank 8)
*/
-
void
-drain_stat (object *op)
+object::drain_stat ()
{
- drain_specific_stat (op, RANDOM () % NUM_STATS);
+ drain_specific_stat (rndm (NUM_STATS));
}
void
-drain_specific_stat (object *op, int deplete_stats)
+object::drain_specific_stat (int deplete_stats)
{
object *tmp;
archetype *at;
- at = find_archetype (ARCH_DEPLETION);
+ at = archetype::find (ARCH_DEPLETION);
if (!at)
{
LOG (llevError, "Couldn't find archetype depletion.\n");
@@ -702,73 +604,72 @@
}
else
{
- tmp = present_arch_in_ob (at, op);
+ tmp = present_arch_in_ob (at, this);
+
if (!tmp)
{
tmp = arch_to_object (at);
- tmp = insert_ob_in_ob (tmp, op);
+ tmp = insert_ob_in_ob (tmp, this);
SET_FLAG (tmp, FLAG_APPLIED);
}
}
- new_draw_info (NDI_UNIQUE, 0, op, drain_msg[deplete_stats]);
+ new_draw_info (NDI_UNIQUE, 0, this, drain_msg[deplete_stats]);
change_attr_value (&tmp->stats, deplete_stats, -1);
- fix_player (op);
+ update_stats ();
}
/*
* A value of 0 indicates timeout, otherwise change the luck of the object.
* via an applied bad_luck object.
*/
-
void
-change_luck (object *op, int value)
+object::change_luck (int value)
{
- object *tmp;
- archetype *at;
- int new_luck;
-
- at = find_archetype ("luck");
+ archetype *at = archetype::find ("luck");
if (!at)
LOG (llevError, "Couldn't find archetype luck.\n");
else
{
- tmp = present_arch_in_ob (at, op);
+ object *tmp = present_arch_in_ob (at, this);
+
if (!tmp)
{
if (!value)
return;
+
tmp = arch_to_object (at);
- tmp = insert_ob_in_ob (tmp, op);
+ tmp = insert_ob_in_ob (tmp, this);
SET_FLAG (tmp, FLAG_APPLIED);
}
+
if (value)
{
/* Limit the luck value of the bad luck object to +/-100. This
* (arbitrary) value prevents overflows (both in the bad luck object and
* in op itself).
*/
- new_luck = tmp->stats.luck + value;
+ int new_luck = tmp->stats.luck + value;
+
if (new_luck >= -100 && new_luck <= 100)
{
- op->stats.luck += value;
+ stats.luck += value;
tmp->stats.luck = new_luck;
}
}
else
{
if (!tmp->stats.luck)
- {
- return;
- }
+ return;
+
/* Randomly change the players luck. Basically, we move it
* back neutral (if greater>0, subtract, otherwise add)
*/
- if (RANDOM () % (FABS (tmp->stats.luck)) >= RANDOM () % 30)
+ if (rndm (abs (tmp->stats.luck)) >= rndm (30))
{
int diff = tmp->stats.luck > 0 ? -1 : 1;
- op->stats.luck += diff;
+ stats.luck += diff;
tmp->stats.luck += diff;
}
}
@@ -778,143 +679,156 @@
/*
* Subtracts stat-bonuses given by the class which the player has chosen.
*/
-
void
-remove_statbonus (object *op)
+object::remove_statbonus ()
{
- op->stats.Str -= op->arch->clone.stats.Str;
- op->stats.Dex -= op->arch->clone.stats.Dex;
- op->stats.Con -= op->arch->clone.stats.Con;
- op->stats.Wis -= op->arch->clone.stats.Wis;
- op->stats.Pow -= op->arch->clone.stats.Pow;
- op->stats.Cha -= op->arch->clone.stats.Cha;
- op->stats.Int -= op->arch->clone.stats.Int;
- op->contr->orig_stats.Str -= op->arch->clone.stats.Str;
- op->contr->orig_stats.Dex -= op->arch->clone.stats.Dex;
- op->contr->orig_stats.Con -= op->arch->clone.stats.Con;
- op->contr->orig_stats.Wis -= op->arch->clone.stats.Wis;
- op->contr->orig_stats.Pow -= op->arch->clone.stats.Pow;
- op->contr->orig_stats.Cha -= op->arch->clone.stats.Cha;
- op->contr->orig_stats.Int -= op->arch->clone.stats.Int;
+ for (int i = 0; i < NUM_STATS; ++i)
+ {
+ sint8 v = arch->stats.stat (i);
+ stats.stat (i) -= v;
+ contr->orig_stats.stat (i) -= v;
+ }
}
/*
* Adds stat-bonuses given by the class which the player has chosen.
*/
-
void
-add_statbonus (object *op)
+object::add_statbonus ()
{
- op->stats.Str += op->arch->clone.stats.Str;
- op->stats.Dex += op->arch->clone.stats.Dex;
- op->stats.Con += op->arch->clone.stats.Con;
- op->stats.Wis += op->arch->clone.stats.Wis;
- op->stats.Pow += op->arch->clone.stats.Pow;
- op->stats.Cha += op->arch->clone.stats.Cha;
- op->stats.Int += op->arch->clone.stats.Int;
- op->contr->orig_stats.Str += op->arch->clone.stats.Str;
- op->contr->orig_stats.Dex += op->arch->clone.stats.Dex;
- op->contr->orig_stats.Con += op->arch->clone.stats.Con;
- op->contr->orig_stats.Wis += op->arch->clone.stats.Wis;
- op->contr->orig_stats.Pow += op->arch->clone.stats.Pow;
- op->contr->orig_stats.Cha += op->arch->clone.stats.Cha;
- op->contr->orig_stats.Int += op->arch->clone.stats.Int;
+ for (int i = 0; i < NUM_STATS; ++i)
+ {
+ sint8 v = arch->stats.stat (i);
+ stats.stat (i) += v;
+ contr->orig_stats.stat (i) += v;
+ }
}
+/* These are the items that currently can change digestion, regeneration,
+ * spell point recovery and mana point recovery. Seems sort of an arbitary
+ * list, but other items store other info into stats array.
+ */
+static struct digest_types : std::bitset
+{
+ digest_types ()
+ {
+ set (WEAPON);
+ set (BOW);
+ set (ARMOUR);
+ set (HELMET);
+ set (SHIELD);
+ set (RING);
+ set (BOOTS);
+ set (GLOVES);
+ set (AMULET);
+ set (GIRDLE);
+ set (BRACERS);
+ set (CLOAK);
+ set (DISEASE);
+ set (FORCE);
+ set (SKILL);
+ }
+} digest_types;
+
+static struct copy_flags : object::flags_t
+{
+ copy_flags ()
+ {
+ set (FLAG_LIFESAVE);
+ set (FLAG_REFL_SPELL);
+ set (FLAG_REFL_MISSILE);
+ set (FLAG_STEALTH);
+ set (FLAG_XRAYS);
+ set (FLAG_BLIND);
+ set (FLAG_SEE_IN_DARK);
+ }
+} copy_flags;
+
/*
* Updates all abilities given by applied objects in the inventory
* of the given object. Note: This function works for both monsters
* and players; the "player" in the name is purely an archaic inheritance.
* This functions starts from base values (archetype or player object)
* and then adjusts them according to what the player has equipped.
+ *
+ * July 95 - inserted stuff to handle new skills/exp system - b.t.
+ * spell system split, grace points now added to system --peterm
*/
-
-/* July 95 - inserted stuff to handle new skills/exp system - b.t.
- spell system split, grace points now added to system --peterm
- */
-
void
-fix_player (object *op)
+object::update_stats ()
{
- int i, j;
- float f, max = 9, added_speed = 0, bonus_speed = 0, sp_tmp, speed_reduce_from_disease = 1;
+ float f, max_speed = 9, added_speed = 0, bonus_speed = 0, speed_reduce_from_disease = 1;
int weapon_weight = 0, weapon_speed = 0;
int best_wc = 0, best_ac = 0, wc = 0, ac = 0;
int prot[NROFATTACKS], vuln[NROFATTACKS], potion_resist[NROFATTACKS];
- object *grace_obj = NULL, *mana_obj = NULL, *wc_obj = NULL, *tmp;
+ object *grace_obj = NULL, *mana_obj = NULL, *tmp;
+ float old_speed = speed;
+ int stat_sum [NUM_STATS];
/* First task is to clear all the values back to their original values */
- if (op->type == PLAYER)
+ if (type == PLAYER)
{
- for (i = 0; i < NUM_STATS; i++)
- {
- set_attr_value (&(op->stats), i, get_attr_value (&(op->contr->orig_stats), i));
- }
+ for (int i = 0; i < NUM_STATS; i++)
+ stat_sum [i] = contr->orig_stats.stat (i);
+
if (settings.spell_encumbrance == TRUE)
- op->contr->encumbrance = 0;
+ contr->encumbrance = 0;
- op->attacktype = 0;
- op->contr->digestion = 0;
- op->contr->gen_hp = 0;
- op->contr->gen_sp = 0;
- op->contr->gen_grace = 0;
- op->contr->gen_sp_armour = 10;
- op->contr->item_power = 0;
-
- /* Don't clobber all the range_ values. range_golem otherwise
- * gets reset for no good reason, and we don't want to reset
- * range_magic (what spell is readied). These three below
- * well get filled in based on what the player has equipped.
- */
- op->contr->ranges[range_bow] = NULL;
- op->contr->ranges[range_misc] = NULL;
- op->contr->ranges[range_skill] = NULL;
- }
- memcpy (op->body_used, op->body_info, sizeof (op->body_info));
-
- op->slaying = 0;
-
- if (!QUERY_FLAG (op, FLAG_WIZ))
- {
- CLEAR_FLAG (op, FLAG_XRAYS);
- CLEAR_FLAG (op, FLAG_MAKE_INVIS);
- }
-
- CLEAR_FLAG (op, FLAG_LIFESAVE);
- CLEAR_FLAG (op, FLAG_STEALTH);
- CLEAR_FLAG (op, FLAG_BLIND);
- if (!QUERY_FLAG (&op->arch->clone, FLAG_REFL_SPELL))
- CLEAR_FLAG (op, FLAG_REFL_SPELL);
- if (!QUERY_FLAG (&op->arch->clone, FLAG_REFL_MISSILE))
- CLEAR_FLAG (op, FLAG_REFL_MISSILE);
- if (!QUERY_FLAG (&op->arch->clone, FLAG_UNDEAD))
- CLEAR_FLAG (op, FLAG_UNDEAD);
- if (!QUERY_FLAG (&op->arch->clone, FLAG_SEE_IN_DARK))
- CLEAR_FLAG (op, FLAG_SEE_IN_DARK);
-
- op->path_attuned = op->arch->clone.path_attuned;
- op->path_repelled = op->arch->clone.path_repelled;
- op->path_denied = op->arch->clone.path_denied;
- op->glow_radius = op->arch->clone.glow_radius;
- op->move_type = op->arch->clone.move_type;
- op->chosen_skill = NULL;
+ attacktype = 0;
+
+ contr->digestion = 0;
+ contr->gen_hp = 0;
+ contr->gen_sp = 0;
+ contr->gen_grace = 0;
+ contr->gen_sp_armour = 10;
+ contr->item_power = 0;
+ }
+
+ for (int i = NUM_BODY_LOCATIONS; i--; )
+ slot[i].used = slot[i].info;
+
+ slaying = 0;
+
+ if (!QUERY_FLAG (this, FLAG_WIZ))
+ {
+ CLEAR_FLAG (this, FLAG_XRAYS);
+ CLEAR_FLAG (this, FLAG_MAKE_INVIS);
+ }
+
+ CLEAR_FLAG (this, FLAG_LIFESAVE);
+ CLEAR_FLAG (this, FLAG_STEALTH);
+ CLEAR_FLAG (this, FLAG_BLIND);
+
+ if (!QUERY_FLAG (arch, FLAG_REFL_SPELL )) CLEAR_FLAG (this, FLAG_REFL_SPELL);
+ if (!QUERY_FLAG (arch, FLAG_REFL_MISSILE)) CLEAR_FLAG (this, FLAG_REFL_MISSILE);
+ if (!QUERY_FLAG (arch, FLAG_UNDEAD )) CLEAR_FLAG (this, FLAG_UNDEAD);
+ if (!QUERY_FLAG (arch, FLAG_SEE_IN_DARK )) CLEAR_FLAG (this, FLAG_SEE_IN_DARK);
+
+ path_attuned = arch->path_attuned;
+ path_repelled = arch->path_repelled;
+ path_denied = arch->path_denied;
+ glow_radius = arch->glow_radius;
+ move_type = arch->move_type;
+
+ chosen_skill = 0;
/* initializing resistances from the values in player/monster's
* archetype clone
*/
- memcpy (&op->resist, &op->arch->clone.resist, sizeof (op->resist));
+ memcpy (&resist, &arch->resist, sizeof (resist));
- for (i = 0; i < NROFATTACKS; i++)
+ for (int i = 0; i < NROFATTACKS; i++)
{
- if (op->resist[i] > 0)
- prot[i] = op->resist[i], vuln[i] = 0;
+ if (resist[i] > 0)
+ prot[i] = resist[i], vuln[i] = 0;
else
- vuln[i] = -(op->resist[i]), prot[i] = 0;
+ vuln[i] = -(resist[i]), prot[i] = 0;
+
potion_resist[i] = 0;
}
- wc = op->arch->clone.stats.wc;
- op->stats.dam = op->arch->clone.stats.dam;
+ wc = arch->stats.wc;
+ stats.dam = arch->stats.dam;
/* for players which cannot use armour, they gain AC -1 per 3 levels,
* plus a small amount of physical resist, those poor suckers. ;)
@@ -923,37 +837,33 @@
* basically, if a server updates its max level, these playes may find
* that their protection from physical goes down
*/
- if (!QUERY_FLAG (op, FLAG_USE_ARMOUR) && op->type == PLAYER)
+ if (!QUERY_FLAG (this, FLAG_USE_ARMOUR) && type == PLAYER)
{
- ac = MAX (-10, op->arch->clone.stats.ac - op->level / 3);
- prot[ATNR_PHYSICAL] += ((100 - prot[AT_PHYSICAL]) * (80 * op->level / settings.max_level)) / 100;
+ ac = max (-10, arch->stats.ac - level / 3);
+ prot[ATNR_PHYSICAL] += ((100 - prot[AT_PHYSICAL]) * (80 * level / settings.max_level)) / 100;
}
else
- ac = op->arch->clone.stats.ac;
+ ac = arch->stats.ac;
- op->stats.luck = op->arch->clone.stats.luck;
- op->speed = op->arch->clone.speed;
+ stats.luck = arch->stats.luck;
+ speed = arch->speed;
/* OK - we've reset most all the objects attributes to sane values.
* now go through and make adjustments for what the player has equipped.
*/
-
- for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
+ for (tmp = inv; tmp; tmp = tmp->below)
{
- /* 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 > op->glow_radius)
- op->glow_radius = tmp->glow_radius;
-
/* This happens because apply_potion calls change_abil with the potion
- * applied so we can tell the player what chagned. But change_abil
+ * applied so we can tell the player what changed. But change_abil
* then calls this function.
*/
if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type == POTION)
- {
- continue;
- }
+ continue;
+
+ /* See note in map.c:update_position about making this additive
+ * since light sources are never applied, need to put check here.
+ */
+ glow_radius = max (glow_radius, tmp->glow_radius);
/* For some things, we don't care what is equipped */
if (tmp->type == SKILL)
@@ -966,6 +876,7 @@
else if (tmp->level > mana_obj->level)
mana_obj = tmp;
}
+
if (IS_GRACE_SKILL (tmp->subtype))
{
if (!grace_obj)
@@ -975,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
@@ -984,248 +895,259 @@
* because the skill shouldn't count against body positions being used
* up, etc.
*/
- if ((QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type != CONTAINER && tmp->type != CLOSE_CON) ||
- (tmp->type == SKILL && tmp->subtype == SK_PRAYING))
- {
- if (op->type == PLAYER)
- {
- if (tmp->type == BOW)
- op->contr->ranges[range_bow] = tmp;
-
- if (tmp->type == WAND || tmp->type == ROD || tmp->type == HORN)
- op->contr->ranges[range_misc] = tmp;
+ if ((tmp->flag [FLAG_APPLIED]
+ && tmp->type != CONTAINER
+ && tmp->type != CLOSE_CON)
+ || (tmp->type == SKILL
+ && tmp->subtype == SK_PRAYING))
+ {
+ if (type == PLAYER)
+ {
+ contr->item_power += tmp->item_power;
+
+ if (tmp == contr->combat_ob || tmp == contr->ranged_ob)
+ if (tmp != current_weapon
+ && (tmp->type != SKILL || tmp->subtype != SK_PRAYING)
+ && !tmp->flag [FLAG_CURSED]
+ && !tmp->flag [FLAG_DAMNED])
+ continue;
- for (i = 0; i < NUM_STATS; i++)
- change_attr_value (&(op->stats), i, get_attr_value (&(tmp->stats), i));
+ for (int i = 0; i < NUM_STATS; i++)
+ stat_sum [i] = stat_sum [i] + tmp->stats.stat (i);
- /* these are the items that currently can change digestion, regeneration,
- * spell point recovery and mana point recovery. Seems sort of an arbitary
- * list, but other items store other info into stats array.
- */
- if ((tmp->type == EXPERIENCE) || (tmp->type == WEAPON) ||
- (tmp->type == ARMOUR) || (tmp->type == HELMET) ||
- (tmp->type == SHIELD) || (tmp->type == RING) ||
- (tmp->type == BOOTS) || (tmp->type == GLOVES) ||
- (tmp->type == AMULET) || (tmp->type == GIRDLE) ||
- (tmp->type == BRACERS) || (tmp->type == CLOAK) || (tmp->type == DISEASE) || (tmp->type == FORCE) || (tmp->type == SKILL))
+ if (digest_types [tmp->type])
{
- op->contr->digestion += tmp->stats.food;
- op->contr->gen_hp += tmp->stats.hp;
- op->contr->gen_sp += tmp->stats.sp;
- op->contr->gen_grace += tmp->stats.grace;
- op->contr->gen_sp_armour += tmp->gen_sp_armour;
- op->contr->item_power += tmp->item_power;
+ contr->digestion += tmp->stats.food;
+ contr->gen_hp += tmp->stats.hp;
+ 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;
}
} /* if this is a player */
+ else
+ {
+ if (tmp->type == WEAPON)
+ current_weapon = tmp;
+ }
/* Update slots used for items */
if (QUERY_FLAG (tmp, FLAG_APPLIED))
- {
- for (i = 0; i < NUM_BODY_LOCATIONS; i++)
- op->body_used[i] += tmp->body_info[i];
- }
+ for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
+ slot[i].used += tmp->slot[i].info;
if (tmp->type == SYMPTOM)
- {
- speed_reduce_from_disease = tmp->last_sp / 100.0;
- if (speed_reduce_from_disease == 0)
- speed_reduce_from_disease = 1;
- }
+ 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).
- * (Negative protections are calculated extactly like positive.)
+ /* 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.
*/
if (tmp->type != POTION)
{
- for (i = 0; i < NROFATTACKS; i++)
+ for (int i = 0; i < NROFATTACKS; i++)
{
/* Potential for cursed potions, in which case we just can use
- * a straight MAX, as potion_resist is initialized to zero.
+ * a straight MAX, as potion_resist is initialised to zero.
*/
if (tmp->type == POTION_EFFECT)
{
if (potion_resist[i])
- potion_resist[i] = MAX (potion_resist[i], tmp->resist[i]);
+ potion_resist[i] = max (potion_resist[i], tmp->resist[i]);
else
potion_resist[i] = tmp->resist[i];
}
else if (tmp->resist[i] > 0)
- prot[i] += ((100 - prot[i]) * tmp->resist[i]) / 100;
+ prot[i] += ((100 - prot[i]) * tmp->resist[i]) / 100;
else if (tmp->resist[i] < 0)
- vuln[i] += ((100 - vuln[i]) * (-tmp->resist[i])) / 100;
+ vuln[i] += ((100 - vuln[i]) * -tmp->resist[i]) / 100;
}
}
/* There may be other things that should not adjust the attacktype */
- if (tmp->type != BOW && tmp->type != SYMPTOM)
- op->attacktype |= tmp->attacktype;
+ if (tmp->type != SYMPTOM)
+ {
+ attacktype |= tmp->attacktype;
+ path_attuned |= tmp->path_attuned;
+ path_repelled |= tmp->path_repelled;
+ path_denied |= tmp->path_denied;
+ move_type |= tmp->move_type;
+ stats.luck += tmp->stats.luck;
+ }
- op->path_attuned |= tmp->path_attuned;
- op->path_repelled |= tmp->path_repelled;
- op->path_denied |= tmp->path_denied;
- op->stats.luck += tmp->stats.luck;
- op->move_type |= tmp->move_type;
-
- if (QUERY_FLAG (tmp, FLAG_LIFESAVE))
- SET_FLAG (op, FLAG_LIFESAVE);
- if (QUERY_FLAG (tmp, FLAG_REFL_SPELL))
- SET_FLAG (op, FLAG_REFL_SPELL);
- if (QUERY_FLAG (tmp, FLAG_REFL_MISSILE))
- SET_FLAG (op, FLAG_REFL_MISSILE);
- if (QUERY_FLAG (tmp, FLAG_STEALTH))
- SET_FLAG (op, FLAG_STEALTH);
- if (QUERY_FLAG (tmp, FLAG_XRAYS))
- SET_FLAG (op, FLAG_XRAYS);
- if (QUERY_FLAG (tmp, FLAG_BLIND))
- SET_FLAG (op, FLAG_BLIND);
- if (QUERY_FLAG (tmp, FLAG_SEE_IN_DARK))
- SET_FLAG (op, FLAG_SEE_IN_DARK);
+ flag |= tmp->flag & copy_flags;
- if (QUERY_FLAG (tmp, FLAG_UNDEAD) && !QUERY_FLAG (&op->arch->clone, FLAG_UNDEAD))
- SET_FLAG (op, FLAG_UNDEAD);
+ if (QUERY_FLAG (tmp, FLAG_UNDEAD) && !QUERY_FLAG (arch, FLAG_UNDEAD))
+ SET_FLAG (this, FLAG_UNDEAD);
if (QUERY_FLAG (tmp, FLAG_MAKE_INVIS))
{
- SET_FLAG (op, FLAG_MAKE_INVIS);
- op->invisible = 1;
+ SET_FLAG (this, FLAG_MAKE_INVIS);
+ invisible = 1;
}
if (tmp->stats.exp && tmp->type != SKILL)
{
if (tmp->stats.exp > 0)
{
- added_speed += (float) tmp->stats.exp / 3.0;
- bonus_speed += 1.0 + (float) tmp->stats.exp / 3.0;
+ added_speed += tmp->stats.exp / 3.f;
+ bonus_speed += tmp->stats.exp / 3.f + 1.f;
}
else
- added_speed += (float) tmp->stats.exp;
+ added_speed += tmp->stats.exp;
}
switch (tmp->type)
{
- /* skills modifying the character -b.t. */
- /* for all skills and skill granting objects */
- case SKILL:
- if (!QUERY_FLAG (tmp, FLAG_APPLIED))
- break;
+#if 0
+ case WAND:
+ case ROD:
+ case HORN:
+ if (type != PLAYER || current_weapon == tmp)
+ chosen_skill = tmp;
+ break;
+#endif
- if (IS_COMBAT_SKILL (tmp->subtype))
- wc_obj = tmp;
+ /* skills modifying the character -b.t. */
+ /* for all skills and skill granting objects */
+ case SKILL:
+ {
+ if (!QUERY_FLAG (tmp, FLAG_APPLIED) || skill_flags [tmp->subtype] & SF_APPLY)
+ break;
- if (op->chosen_skill)
+ if (chosen_skill)
{
- LOG (llevDebug, "fix_player, op %s has multiple skills applied\n", &op->name);
+ LOG (llevDebug, "fix_player, op %s has multiple skills applied (%s and %s)\n",
+ &name, &chosen_skill->name, &tmp->name);
+
+ tmp->flag [FLAG_APPLIED] = false;
+ update_stats ();
+ return;
}
- op->chosen_skill = tmp;
+ else
+ chosen_skill = tmp;
+
if (tmp->stats.dam > 0)
- { /* skill is a 'weapon' */
- if (!QUERY_FLAG (op, FLAG_READY_WEAPON))
- weapon_speed = (int) WEAPON_SPEED (tmp);
+ { /* skill is a 'weapon' */
+ if (!QUERY_FLAG (this, FLAG_READY_WEAPON))
+ weapon_speed = WEAPON_SPEED (tmp);
+
if (weapon_speed < 0)
weapon_speed = 0;
+
weapon_weight = tmp->weight;
- op->stats.dam += tmp->stats.dam * (1 + (op->chosen_skill->level / 9));
+ stats.dam += 1 + chosen_skill->level * tmp->stats.dam / 9;
+
if (tmp->magic)
- op->stats.dam += tmp->magic;
+ stats.dam += tmp->magic;
}
+
if (tmp->stats.wc)
- wc -= (tmp->stats.wc + tmp->magic);
+ wc -= tmp->stats.wc + tmp->magic;
- if (tmp->slaying != NULL)
- op->slaying = tmp->slaying;
+ if (tmp->slaying)
+ slaying = tmp->slaying;
if (tmp->stats.ac)
- ac -= (tmp->stats.ac + tmp->magic);
- if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
- op->contr->encumbrance += (int) 3 *tmp->weight / 1000;
-
- if (op->type == PLAYER)
- op->contr->ranges[range_skill] = op;
- break;
+ ac -= tmp->stats.ac + tmp->magic;
- case SKILL_TOOL:
- if (op->chosen_skill)
- {
- LOG (llevDebug, "fix_player, op %s has multiple skills applied\n", &op->name);
- }
- op->chosen_skill = tmp;
- if (op->type == PLAYER)
- op->contr->ranges[range_skill] = op;
- break;
-
- case SHIELD:
- if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
- op->contr->encumbrance += (int) tmp->weight / 2000;
- case RING:
- case AMULET:
- case GIRDLE:
- case HELMET:
- case BOOTS:
- case GLOVES:
- case CLOAK:
- if (tmp->stats.wc)
- wc -= (tmp->stats.wc + tmp->magic);
- if (tmp->stats.dam)
- op->stats.dam += (tmp->stats.dam + tmp->magic);
- if (tmp->stats.ac)
- ac -= (tmp->stats.ac + tmp->magic);
- break;
+ if (settings.spell_encumbrance == TRUE && type == PLAYER)
+ contr->encumbrance += (int) 3 *tmp->weight / 1000;
+ }
+
+ break;
+
+ case SHIELD:
+ if (settings.spell_encumbrance == TRUE && type == PLAYER)
+ contr->encumbrance += (int) tmp->weight / 2000;
+ case RING:
+ case AMULET:
+ case GIRDLE:
+ case HELMET:
+ case BOOTS:
+ case GLOVES:
+ case CLOAK:
+ if (tmp->stats.wc)
+ wc -= tmp->stats.wc + tmp->magic;
+
+ if (tmp->stats.dam)
+ stats.dam += tmp->stats.dam + tmp->magic;
+
+ if (tmp->stats.ac)
+ ac -= tmp->stats.ac + tmp->magic;
- case WEAPON:
+ break;
+
+ case BOW:
+ case WEAPON:
+ if (type != PLAYER || current_weapon == tmp)
+ {
+ wc -= tmp->stats.wc + tmp->magic;
+
+ if (tmp->stats.ac && tmp->stats.ac + tmp->magic > 0)
+ ac -= tmp->stats.ac + tmp->magic;
+
+ stats.dam += tmp->stats.dam + tmp->magic;
+ weapon_weight = tmp->weight;
+ weapon_speed = (WEAPON_SPEED (tmp) * 2 - tmp->magic) / 2;
+
+ if (weapon_speed < 0)
+ weapon_speed = 0;
+
+ slaying = tmp->slaying;
+
+ /* If there is desire that two handed weapons should do
+ * extra strength damage, this is where the code should
+ * go.
+ */
+
+ if (type == PLAYER)
+ if (settings.spell_encumbrance)
+ contr->encumbrance += tmp->weight * 3 / 1000;
+ }
+
+ break;
+
+ case ARMOUR: /* Only the best of these three are used: */
+ if (settings.spell_encumbrance == TRUE && type == PLAYER)
+ contr->encumbrance += tmp->weight / 1000;
+
+ case BRACERS:
+ case FORCE:
+ if (tmp->stats.wc)
+ {
+ if (best_wc < tmp->stats.wc + tmp->magic)
+ {
+ wc += best_wc;
+ best_wc = tmp->stats.wc + tmp->magic;
+ }
+ else
+ wc += tmp->stats.wc + tmp->magic;
+ }
+
+ if (tmp->stats.ac)
+ {
+ if (best_ac < tmp->stats.ac + tmp->magic)
+ {
+ ac += best_ac; /* Remove last bonus */
+ best_ac = tmp->stats.ac + tmp->magic;
+ }
+ else /* To nullify the below effect */
+ ac += tmp->stats.ac + tmp->magic;
+ }
+
+ if (tmp->stats.wc)
wc -= (tmp->stats.wc + tmp->magic);
- if (tmp->stats.ac && tmp->stats.ac + tmp->magic > 0)
- ac -= tmp->stats.ac + tmp->magic;
- op->stats.dam += (tmp->stats.dam + tmp->magic);
- weapon_weight = tmp->weight;
- weapon_speed = ((int) WEAPON_SPEED (tmp) * 2 - tmp->magic) / 2;
- if (weapon_speed < 0)
- weapon_speed = 0;
- op->slaying = tmp->slaying;
- /* If there is desire that two handed weapons should do
- * extra strength damage, this is where the code should
- * go.
- */
- op->current_weapon = tmp;
- if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
- op->contr->encumbrance += (int) 3 *tmp->weight / 1000;
-
- break;
-
- case ARMOUR: /* Only the best of these three are used: */
- if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
- op->contr->encumbrance += (int) tmp->weight / 1000;
- case BRACERS:
- case FORCE:
- if (tmp->stats.wc)
- {
- if (best_wc < tmp->stats.wc + tmp->magic)
- {
- wc += best_wc;
- best_wc = tmp->stats.wc + tmp->magic;
- }
- else
- wc += tmp->stats.wc + tmp->magic;
- }
- if (tmp->stats.ac)
- {
- if (best_ac < tmp->stats.ac + tmp->magic)
- {
- ac += best_ac; /* Remove last bonus */
- best_ac = tmp->stats.ac + tmp->magic;
- }
- else /* To nullify the below effect */
- ac += tmp->stats.ac + tmp->magic;
- }
- if (tmp->stats.wc)
- wc -= (tmp->stats.wc + tmp->magic);
- if (tmp->stats.ac)
- ac -= (tmp->stats.ac + tmp->magic);
- if (ARMOUR_SPEED (tmp) && ARMOUR_SPEED (tmp) / 10.0 < max)
- max = ARMOUR_SPEED (tmp) / 10.0;
- break;
+ if (tmp->stats.ac)
+ ac -= (tmp->stats.ac + tmp->magic);
+
+ if (ARMOUR_SPEED (tmp))
+ max_speed = min (max_speed, ARMOUR_SPEED (tmp) / 10.f);
+
+ break;
} /* switch tmp->type */
} /* item is equipped */
} /* for loop of items */
@@ -1240,20 +1162,27 @@
* If there is a cursed (and no uncursed) potion in effect, we take
* 'total resistance = vulnerability from cursed potion'.
*/
- for (i = 0; i < NROFATTACKS; i++)
+ for (int i = 0; i < NROFATTACKS; i++)
{
- op->resist[i] = prot[i] - vuln[i];
- if (potion_resist[i] && ((potion_resist[i] > op->resist[i]) || (potion_resist[i] < 0)))
- op->resist[i] = potion_resist[i];
+ resist[i] = prot[i] - vuln[i];
+
+ if (potion_resist[i] && ((potion_resist[i] > resist[i]) || (potion_resist[i] < 0)))
+ resist[i] = potion_resist[i];
}
- /* Figure out the players sp/mana/hp totals. */
- if (op->type == PLAYER)
+ if (type == PLAYER)
{
+ // clamp various player stats
+ for (int i = 0; i < NUM_STATS; ++i)
+ stats.stat (i) = clamp (stat_sum [i], MIN_STAT, MAX_STAT);
+
+ contr->digestion = clamp (contr->digestion, MIN_DIGESTION, MAX_DIGESTION);
+
+ /* Figure out the players sp/mana/hp totals. */
int pl_level;
- check_stat_bounds (&(op->stats));
- pl_level = op->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! */
@@ -1261,78 +1190,70 @@
/* 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.
*/
- for (i = 1, op->stats.maxhp = 0; i <= pl_level && i <= 10; i++)
+ stats.maxhp = 0;
+ for (int i = 1; i <= min (10, pl_level); i++)
{
- j = op->contr->levhp[i] + con_bonus[op->stats.Con] / 2;
- if (i % 2 && con_bonus[op->stats.Con] % 2)
- {
- if (con_bonus[op->stats.Con] > 0)
- j++;
- else
- j--;
- }
- op->stats.maxhp += j > 1 ? j : 1; /* always get at least 1 hp/level */
+ int j = contr->levhp[i] + con_bonus[stats.Con] / 2;
+
+ if (i % 2 && con_bonus[stats.Con] % 2)
+ if (con_bonus[stats.Con] > 0)
+ j++;
+ else
+ j--;
+
+ stats.maxhp += j > 1 ? j : 1; /* always get at least 1 hp/level */
}
- for (i = 11; i <= op->level; i++)
- op->stats.maxhp += 2;
+ stats.maxhp += 2 * max (0, level - 10);
- if (op->stats.hp > op->stats.maxhp)
- op->stats.hp = op->stats.maxhp;
+ if (stats.hp > stats.maxhp)
+ stats.hp = stats.maxhp;
/* Sp gain is controlled by the level of the player's
* relevant experience object (mana_obj, see above)
*/
/* following happen when skills system is not used */
if (!mana_obj)
- mana_obj = op;
+ mana_obj = this;
+
if (!grace_obj)
- grace_obj = op;
+ grace_obj = this;
+
/* set maxsp */
- if (!mana_obj || !mana_obj->level || op->type != PLAYER)
- mana_obj = op;
+ if (!mana_obj || !mana_obj->level || type != PLAYER)
+ mana_obj = this;
- if (mana_obj == op && op->type == PLAYER)
- {
- op->stats.maxsp = 1;
- }
+ if (mana_obj == this && type == PLAYER)
+ stats.maxsp = 1;
else
{
- sp_tmp = 0.0;
- for (i = 1; i <= mana_obj->level && i <= 10; i++)
+ float sp_tmp = 0.f;
+
+ for (int i = 1; i <= min (10, mana_obj->level); i++)
{
float stmp;
/* Got some extra bonus at first level */
if (i < 2)
- {
- stmp = op->contr->levsp[i] + ((2.0 * (float) sp_bonus[op->stats.Pow] + (float) sp_bonus[op->stats.Int]) / 6.0);
- }
+ stmp = contr->levsp[i] + (2.f * sp_bonus[stats.Pow] + sp_bonus[stats.Int]) / 6.f;
else
- {
- stmp = (float) op->contr->levsp[i] + (2.0 * (float) sp_bonus[op->stats.Pow] + (float) sp_bonus[op->stats.Int]) / 12.0;
- }
- if (stmp < 1.0)
- stmp = 1.0;
- sp_tmp += stmp;
+ stmp = contr->levsp[i] + (2.f * sp_bonus[stats.Pow] + sp_bonus[stats.Int]) / 12.f;
+
+ sp_tmp += max (1.f, stmp);
}
- op->stats.maxsp = (int) sp_tmp;
- for (i = 11; i <= mana_obj->level; i++)
- op->stats.maxsp += 2;
+ stats.maxsp = int (sp_tmp) + 2 * max (0, mana_obj->level - 10);
}
+
/* Characters can get their sp supercharged via rune of transferrance */
- if (op->stats.sp > op->stats.maxsp * 2)
- op->stats.sp = op->stats.maxsp * 2;
+ stats.sp = min (stats.sp, stats.maxsp * 2);
/* set maxgrace, notice 3-4 lines below it depends on both Wis and Pow */
- if (!grace_obj || !grace_obj->level || op->type != PLAYER)
- grace_obj = op;
+ if (!grace_obj || !grace_obj->level || type != PLAYER)
+ grace_obj = this;
- if (grace_obj == op && op->type == PLAYER)
- {
- op->stats.maxgrace = 1;
- }
+ if (grace_obj == this && type == PLAYER)
+ stats.maxgrace = 1;
else
{
/* store grace in a float - this way, the divisions below don't create
@@ -1340,41 +1261,34 @@
* becomes big jumps when the sums of the bonuses jump to the next
* step of 8 - with floats, even fractional ones are useful.
*/
- sp_tmp = 0.0;
- for (i = 1, op->stats.maxgrace = 0; i <= grace_obj->level && i <= 10; i++)
+ float sp_tmp = 0.f;
+
+ for (int i = 1; i <= min (10, grace_obj->level); i++)
{
- float grace_tmp = 0.0;
+ float grace_tmp = 0.f;
/* Got some extra bonus at first level */
if (i < 2)
- {
- grace_tmp = op->contr->levgrace[i] + (((float) grace_bonus[op->stats.Pow] +
- 2.0 * (float) grace_bonus[op->stats.Wis]) / 6.0);
- }
+ grace_tmp = contr->levgrace[i] + (grace_bonus[stats.Pow] + 2.f * grace_bonus[stats.Wis]) / 6.f;
else
- {
- grace_tmp = (float) op->contr->levgrace[i]
- + ((float) grace_bonus[op->stats.Pow] + 2.0 * (float) grace_bonus[op->stats.Wis]) / 12.0;
- }
- if (grace_tmp < 1.0)
- grace_tmp = 1.0;
- sp_tmp += grace_tmp;
+ grace_tmp = contr->levgrace[i] + (grace_bonus[stats.Pow] + 2.f * grace_bonus[stats.Wis]) / 12.f;
+
+ sp_tmp += max (1.f, grace_tmp);
}
- op->stats.maxgrace = (int) sp_tmp;
- /* two grace points per level after 11 */
- for (i = 11; i <= grace_obj->level; i++)
- op->stats.maxgrace += 2;
+ /* two grace points per level after 10 */
+ stats.maxgrace = int (sp_tmp) + 2 * max (0, grace_obj->level - 10);
}
+
/* No limit on grace vs maxgrace */
- if (op->contr->braced)
+ if (contr->braced)
{
ac += 2;
wc += 4;
}
else
- ac -= dex_bonus[op->stats.Dex];
+ ac -= dex_bonus[stats.Dex];
/* In new exp/skills system, wc bonuses are related to
* the players level in a relevant exp object (wc_obj)
@@ -1387,107 +1301,100 @@
* to make up for the change. Note that I left the
* monster bonus the same as before. -b.t.
*/
+ object *wc_obj = chosen_skill;
- if (op->type == PLAYER && wc_obj && wc_obj->level > 1)
+ if (contr && wc_obj && wc_obj->level > 1)
{
- wc -= (wc_obj->level + thaco_bonus[op->stats.Str]);
- for (i = 1; i < wc_obj->level; i++)
+ wc -= wc_obj->level + thaco_bonus[stats.Str];
+
+ for (int i = 1; i < wc_obj->level; i++)
{
- /* addtional wc every 6 levels */
+ /* additional wc every 6 levels */
if (!(i % 6))
wc--;
- /* addtional dam every 4 levels. */
- if (!(i % 4) && (dam_bonus[op->stats.Str] >= 0))
- op->stats.dam += (1 + (dam_bonus[op->stats.Str] / 5));
+
+ /* additional dam every 4 levels. */
+ if (!(i % 4) && dam_bonus[stats.Str] >= 0)
+ stats.dam += 1 + dam_bonus[stats.Str] / 5;
}
}
else
- wc -= (op->level + thaco_bonus[op->stats.Str]);
+ wc -= level + thaco_bonus[stats.Str];
- op->stats.dam += dam_bonus[op->stats.Str];
+ stats.dam += dam_bonus[stats.Str];
- if (op->stats.dam < 1)
- op->stats.dam = 1;
+ if (stats.dam < 1)
+ stats.dam = 1;
- op->speed = 1.0 + speed_bonus[op->stats.Dex];
- if (settings.search_items && op->contr->search_str[0])
- op->speed -= 1;
- if (op->attacktype == 0)
- op->attacktype = op->arch->clone.attacktype;
+ speed = 1.f + speed_bonus[stats.Dex];
+ if (settings.search_items && contr->search_str[0])
+ speed -= 1;
+
+ if (attacktype == 0)
+ attacktype = arch->attacktype;
} /* End if player */
if (added_speed >= 0)
- op->speed += added_speed / 10.0;
+ speed += added_speed / 10.f;
else /* Something wrong here...: */
- op->speed /= (float) (1.0 - added_speed);
+ speed /= 1.f - added_speed;
/* Max is determined by armour */
- if (op->speed > max)
- op->speed = max;
+ speed = min (speed, max_speed);
- if (op->type == PLAYER)
+ if (type == PLAYER)
{
/* f is a number the represents the number of kg above (positive num)
* or below (negative number) that the player is carrying. If above
* weight limit, then player suffers a speed reduction based on how
* much above he is, and what is max carry is
*/
- f = (op->carrying / 1000) - max_carry[op->stats.Str];
- if (f > 0)
- op->speed = op->speed / (1.0 + f / max_carry[op->stats.Str]);
+ float f = (carrying / 1000) - max_carry[stats.Str];
+ if (f > 0.f)
+ speed = speed / (1.f + f / max_carry[stats.Str]);
}
- op->speed += bonus_speed / 10.0; /* Not affected by limits */
+ speed += bonus_speed / 10.f; /* Not affected by limits */
+ speed *= speed_reduce_from_disease;
/* Put a lower limit on speed. Note with this speed, you move once every
- * 100 ticks or so. This amounts to once every 12 seconds of realtime.
+ * 25 ticks or so. This amounts to once every 3 seconds of realtime.
*/
- op->speed = op->speed * speed_reduce_from_disease;
+ if (speed < 0.04f && type == PLAYER)
+ speed = 0.04f;
- if (op->speed < 0.01 && op->type == PLAYER)
- op->speed = 0.01;
+ if (speed != old_speed)
+ set_speed (speed);
- if (op->type == PLAYER)
+ if (type == PLAYER)
{
- float M, W, s, D, K, S, M2;
-
/* (This formula was made by vidarl@ifi.uio.no)
* Note that we never used these values again - basically
* all of these could be subbed into one big equation, but
* that would just be a real pain to read.
*/
- M = (max_carry[op->stats.Str] - 121) / 121.0;
- M2 = max_carry[op->stats.Str] / 100.0;
- W = weapon_weight / 20000.0;
- s = 2 - weapon_speed / 10.0;
- D = (op->stats.Dex - 14) / 14.0;
- K = 1 + M / 3.0 - W / (3 * M2) + op->speed / 5.0 + D / 2.0;
- K *= (4 + op->level) / (float) (6 + op->level) * 1.2;
- if (K <= 0)
- K = 0.01;
- S = op->speed / (K * s);
- op->contr->weapon_sp = S;
+ float M = (max_carry[stats.Str] - 121) / 121.f;
+ float M2 = max_carry[stats.Str] / 100.f;
+ float W = weapon_weight / 20000.f;
+ float s = (20 - weapon_speed) / 10.f;
+ float D = (stats.Dex - 14) / 14.f;
+ float K = 1 + M / 3.f - W / (3 * M2) + speed / 5.f + D / 2.f;
+
+ K *= (4 + level) * 1.2f / (6 + level);
+
+ if (K <= 0.01f)
+ K = 0.01f;
+
+ contr->weapon_sp = K * s * .5f; //TODO: balance the .5
}
+
/* I want to limit the power of small monsters with big weapons: */
- if (op->type != PLAYER && op->arch != NULL && op->stats.dam > op->arch->clone.stats.dam * 3)
- op->stats.dam = op->arch->clone.stats.dam * 3;
+ if (type != PLAYER && arch && stats.dam > arch->stats.dam * 3)
+ stats.dam = arch->stats.dam * 3;
- /* Prevent overflows of wc - best you can get is ABS(120) - this
- * should be more than enough - remember, AC is also in 8 bits,
- * so its value is the same.
- */
- if (wc > 120)
- wc = 120;
- else if (wc < -120)
- wc = -120;
- op->stats.wc = wc;
-
- if (ac > 120)
- ac = 120;
- else if (ac < -120)
- ac = -120;
- op->stats.ac = ac;
+ stats.wc = clamp (wc, MIN_WC, MAX_WC);
+ stats.ac = clamp (ac, MIN_AC, MAX_AC);
/* if for some reason the creature doesn't have any move type,
* give them walking as a default.
@@ -1495,18 +1402,23 @@
* old behaviour - if your flying, your not walking - just
* one or the other.
*/
- if (op->move_type == 0)
- op->move_type = MOVE_WALK;
- else if (op->move_type & (MOVE_FLY_LOW | MOVE_FLY_HIGH))
- op->move_type &= ~MOVE_WALK;
-
- update_ob_speed (op);
+ if (move_type == 0)
+ move_type = MOVE_WALK;
+ else if (move_type & (MOVE_FLY_LOW | MOVE_FLY_HIGH))
+ move_type &= ~MOVE_WALK;
/* It is quite possible that a player's spell costing might have changed,
* so we will check that now.
*/
- if (op->type == PLAYER)
- esrv_update_spells (op->contr);
+ if (type == PLAYER)
+ {
+ esrv_update_stats (contr);
+ esrv_update_spells (contr);
+ }
+
+ // update the mapspace, if we are on a map
+ if (!flag [FLAG_REMOVED] && map)
+ map->at (x, y).flags_ = 0;
}
/*
@@ -1516,23 +1428,22 @@
* merely checks that all stats are 1 or more, and returns
* false otherwise.
*/
-
int
allowed_class (const object *op)
{
- return op->stats.Dex > 0 && op->stats.Str > 0 && op->stats.Con > 0 &&
- op->stats.Int > 0 && op->stats.Wis > 0 && op->stats.Pow > 0 && op->stats.Cha > 0;
+ return op->stats.Dex > 0
+ && op->stats.Str > 0
+ && op->stats.Con > 0
+ && op->stats.Int > 0
+ && op->stats.Wis > 0
+ && op->stats.Pow > 0
+ && op->stats.Cha > 0;
}
/*
* 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)
@@ -1560,29 +1471,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 != NULL)
+ 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, "");
@@ -1602,16 +1501,13 @@
char buf[MAX_BUF]; /* tmp. string buffer */
/* now grab the 'dragon_ability'-forces from the player's inventory */
- for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
- {
- if (tmp->type == FORCE)
- {
- if (strcmp (tmp->arch->name, "dragon_ability_force") == 0)
- abil = tmp;
- if (strcmp (tmp->arch->name, "dragon_skin_force") == 0)
- skin = tmp;
- }
- }
+ for (tmp = who->inv; tmp; tmp = tmp->below)
+ if (tmp->type == FORCE)
+ if (tmp->arch->archname == shstr_dragon_ability_force)
+ abil = tmp;
+ else if (tmp->arch->archname == shstr_dragon_skin_force)
+ skin = tmp;
+
/* if the force is missing -> bail out */
if (abil == NULL)
return;
@@ -1662,25 +1558,24 @@
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;
}
+
/* clear the flag - exp goes into this bucket, but player
* still doesn't know it.
*/
CLEAR_FLAG (skill_obj, FLAG_CAN_USE_SKILL);
skill_obj->stats.exp = 0;
skill_obj->level = 1;
- insert_ob_in_ob (skill_obj, op);
- if (op->contr)
- {
- op->contr->last_skill_ob[skill_obj->subtype] = skill_obj;
- op->contr->last_skill_exp[skill_obj->subtype] = -1;
- }
+ op->insert (skill_obj);
+
+ if (player *pl = op->contr)
+ pl->link_skills ();
+
return skill_obj;
}
-
/* player_lvl_adj() - for the new exp system. we are concerned with
* whether the player gets more hp, sp and new levels.
* Note this this function should only be called for players. Monstes
@@ -1692,15 +1587,18 @@
player_lvl_adj (object *who, object *op)
{
char buf[MAX_BUF];
+ bool changed = false;
if (!op) /* when rolling stats */
op = who;
- if (op->level < settings.max_level && op->stats.exp >= level_exp (op->level + 1, who->expmul))
+ while (op->level < settings.max_level && op->stats.exp >= level_exp (op->level + 1, who->expmul))
{
+ changed = true;
+
op->level++;
- if (op != NULL && op == who && op->stats.exp > 1 && is_dragon_pl (who))
+ if (op && op == who && op->stats.exp > 1 && is_dragon_pl (who))
dragon_level_gain (who);
/* Only roll these if it is the player (who) that gained the level */
@@ -1711,31 +1609,44 @@
who->contr->levgrace[who->level] = die_roll (2, 2, who, PREFER_HIGH) - 1;
}
- fix_player (who);
if (op->level > 1)
{
if (op->type != PLAYER)
- sprintf (buf, "You are now level %d in the %s skill.", op->level, &op->name);
+ {
+ who->contr->play_sound (sound_find ("skill_up"));
+ sprintf (buf, "You are now level %d in the %s skill.", op->level, &op->name);
+ }
else
- sprintf (buf, "You are now level %d.", op->level);
+ {
+ who->contr->play_sound (sound_find ("level_up"));
+ sprintf (buf, "You are now level %d.", op->level);
+ }
+
if (who)
new_draw_info (NDI_UNIQUE | NDI_RED, 0, who, buf);
}
- player_lvl_adj (who, op); /* To increase more levels */
}
- else if (op->level > 1 && op->stats.exp < level_exp (op->level, who->expmul))
+
+ while (op->level > 1 && op->stats.exp < level_exp (op->level, who->expmul))
{
+ changed = true;
+
op->level--;
- fix_player (who);
+
if (op->type != PLAYER)
{
sprintf (buf, "You are now level %d in the %s skill.", op->level, &op->name);
new_draw_info (NDI_UNIQUE | NDI_RED, 0, who, buf);
}
- player_lvl_adj (who, op); /* To decrease more levels */
}
- /* check if the spell data has changed */
- esrv_update_spells (who->contr);
+
+ if (changed)
+ {
+ who->update_stats ();
+ esrv_update_stats (who->contr);
+ /* check if the spell data has changed */
+ esrv_update_spells (who->contr);
+ }
}
/*
@@ -1748,6 +1659,7 @@
{
if (level > settings.max_level)
return (sint64) (expmul * levels[settings.max_level]);
+
return (sint64) (expmul * levels[level]);
}
@@ -1778,7 +1690,6 @@
op->perm_exp = MAX_EXPERIENCE;
}
-
/* Add experience to a player - exp should only be positive.
* Updates permanent exp for the skill we are adding to.
* skill_name is the skill to add exp to. Skill name can be
@@ -1786,46 +1697,38 @@
* total, but not any particular skill.
* flag is what to do if the player doesn't have the skill:
*/
-
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;
/* prevents some forms of abuse. */
if (op->contr->braced)
- exp = exp / 5;
+ exp /= 5;
/* Try to find the matching skill.
* We do a shortcut/time saving mechanism first - see if it matches
- * chosen_skill. This means we don't need to search through
+ * 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);
}
}
@@ -1902,7 +1805,6 @@
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,
@@ -1925,7 +1827,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;
@@ -1941,6 +1843,7 @@
player_lvl_adj (op, tmp);
}
}
+
if (flag != SK_SUBTRACT_SKILL_EXP)
{
del_exp = check_exp_loss (op, exp);
@@ -1949,8 +1852,6 @@
}
}
-
-
/* change_exp() - changes experience to a player/monster. This
* does bounds checking to make sure we don't overflow the max exp.
*
@@ -1960,17 +1861,11 @@
* flag is what to do if player doesn't have the skill.
* these last two values are only used for players.
*/
-
void
change_exp (object *op, sint64 exp, const char *skill_name, int flag)
{
-
#ifdef EXP_DEBUG
-# ifndef WIN32
- LOG (llevDebug, "change_exp() called for %s, exp = %lld\n", query_name (op), exp);
-# else
- LOG (llevDebug, "change_exp() called for %s, exp = %I64d\n", query_name (op), exp);
-# endif
+ LOG (llevDebug, "change_exp() called for %s, exp = %" PRId64 "\n", query_name (op), exp);
#endif
/* safety */
@@ -2019,8 +1914,7 @@
* a particular skill, so we don't need to pass that
* along.
*/
- subtract_player_exp (op, FABS (exp), skill_name, flag);
-
+ subtract_player_exp (op, abs (exp), skill_name, flag);
}
}
@@ -2028,7 +1922,6 @@
* settings death_penalty_percentage and death_penalty_levels, and by the
* amount of permenent experience, whichever gives the lowest loss.
*/
-
void
apply_death_exp_penalty (object *op)
{
@@ -2060,6 +1953,7 @@
percentage_loss = op->stats.exp * settings.death_penalty_ratio / 100;
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));
@@ -2083,5 +1977,6 @@
if ((random_roll (1, 20, op, PREFER_HIGH) + bonus) < savethrow[level])
return 0;
+
return 1;
}