ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/living.C
Revision: 1.10
Committed: Tue Sep 12 02:06:19 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.9: +168 -173 lines
Log Message:
indent

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5     Copyright (C) 1992 Frank Tore Johansen
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21     The authors can be reached via e-mail at crossfire-devel@real-time.com
22     */
23    
24     #include <global.h>
25     #include <funcpoint.h>
26    
27     /* Handy little macro that adds exp and keeps it within bounds. Since
28     * we are now using 64 bit values, I'm not all concerned about overflow issues
29     * with exptotal wrapping. exptotal is typically op->exp, or op->perm_exp
30     */
31     #define ADD_EXP(exptotal, exp) {exptotal += exp; if (exptotal > MAX_EXPERIENCE) exptotal = MAX_EXPERIENCE; }
32    
33 root 1.9 static const int con_bonus[MAX_STAT + 1] = {
34     -6, -5, -4, -3, -2, -1, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20,
35     22, 25, 30, 40, 50
36 elmex 1.1 };
37    
38     /* changed the name of this to "sp_bonus" from "int_bonus"
39     * because Pow can now be the stat that controls spellpoint
40     * advancement. -b.t.
41     */
42 root 1.9 static const int sp_bonus[MAX_STAT + 1] = {
43     -10, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25,
44     30, 40, 50, 70, 100
45 elmex 1.1 };
46    
47 root 1.9 static const int grace_bonus[MAX_STAT + 1] = {
48     -10, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25,
49     30, 40, 50, 70, 100
50 elmex 1.1 };
51    
52     /* 0.92.7 Changed way charisma works. Values now
53     * represent how much more it costs to buy something than to sell it
54     * (10, a value of 10 means it is that if it costs 50 gp to buy, you
55     * would only get 5 gp when you sell.) Let query_cost do the calculations
56     * on how to really do this. Buy keeping it this simple number, it is
57     * much easier to know how things will be influenced. A value of '1' means
58     * buying and selling is both the same value - any value less than or equal
59     * to 1 should not be used.
60     * At least as of now, the only place that uses this code is query_cost,
61     * in server/shop.c. This bonus is split evenly between buying and selling
62     * (ie, if the bonus is 2.0, then items are bought for 1.33 list, and sold
63     * at .667
64     * This is figured by diff=(y-1)/(1+y), and for buy, it is 1+diff, for sell
65     * it is 1-diff
66     */
67    
68     const float cha_bonus[MAX_STAT + 1] = { 10.0,
69 root 1.9 10.0, 9.0, 8.0, 7.0, 6.0, /* 5 */
70     5.0, 4.5, 4.0, 3.5, 3.0, /* 10 */
71     2.9, 2.8, 2.7, 2.6, 2.5, /* 15 */
72     2.4, 2.3, 2.2, 2.1, 2.0, /* 20 */
73     1.9, 1.8, 1.7, 1.6, 1.5, /* 25 */
74     1.4, 1.3, 1.2, 1.1, 1.0 /* 30 */
75 elmex 1.1 };
76    
77 root 1.9 const int dex_bonus[MAX_STAT + 1] = {
78     -4, -3, -2, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7
79 elmex 1.1 };
80    
81     /* speed_bonus uses dex as its stat */
82 root 1.9 const float speed_bonus[MAX_STAT + 1] = {
83 elmex 1.1 -0.4, -0.35, -0.3, -0.25, -0.2, -0.16, -0.12, -0.09, -0.06, -0.03, -0.01, 0, 0.01, 0.03,
84     0.05, 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.2, 1.4,
85     1.6, 1.8, 2.0, 2.5, 3.0
86     };
87    
88     /* dam_bonus, thaco_bonus, max_carry, weight limit all are based on
89     * strength.
90     */
91 root 1.9 const int dam_bonus[MAX_STAT + 1] = {
92     -2, -2, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 10, 15
93 elmex 1.1 };
94    
95 root 1.9 const int thaco_bonus[MAX_STAT + 1] = {
96     -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7, 8, 10
97 elmex 1.1 };
98    
99     /* Max you can carry before you start getting extra speed penalties */
100 root 1.9 const int max_carry[MAX_STAT + 1] = {
101     2, 4, 7, 11, 16, 22, 29, 37, 46, 56, 67, 79, 92, 106, 121, 137, 154, 172, 191, 211, 232, 254, 277,
102     301, 326, 352, 400, 450, 500, 600, 1000
103 elmex 1.1 };
104    
105     /* weight_limit - the absolute most a character can carry - a character can't
106     * pick stuff up if it would put him above this limit.
107     * value is in grams, so we don't need to do conversion later
108     * These limits are probably overly generous, but being there were no values
109     * before, you need to start someplace.
110     */
111    
112 root 1.9 const uint32 weight_limit[MAX_STAT + 1] = {
113     200000, /* 0 */
114     250000, 300000, 350000, 400000, 500000, /* 5 */
115     600000, 700000, 800000, 900000, 1000000, /* 10 */
116     1100000, 1200000, 1300000, 1400000, 1500000, /* 15 */
117     1650000, 1800000, 1950000, 2100000, 2250000, /* 20 */
118     2400000, 2550000, 2700000, 2850000, 3000000, /* 25 */
119     3250000, 3500000, 3750000, 4000000, 4500000 /*30 */
120 elmex 1.1 };
121    
122 root 1.9 const int learn_spell[MAX_STAT + 1] = {
123     0, 0, 0, 1, 2, 4, 8, 12, 16, 25, 36, 45, 55, 65, 70, 75, 80, 85, 90, 95, 100, 100, 100, 100, 100,
124     100, 100, 100, 100, 100, 100
125 elmex 1.1 };
126    
127 root 1.9 const int cleric_chance[MAX_STAT + 1] = {
128     100, 100, 100, 100, 90, 80, 70, 60, 50, 40, 35, 30, 25, 20, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0
129 elmex 1.1 };
130    
131 root 1.9 const int turn_bonus[MAX_STAT + 1] = {
132     -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 15
133 elmex 1.1 };
134    
135 root 1.9 const int fear_bonus[MAX_STAT + 1] = {
136     3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
137 elmex 1.1 };
138    
139     /*
140     Since this is nowhere defined ...
141     Both come in handy at least in function add_exp()
142     */
143    
144     #define MAX_EXPERIENCE levels[settings.max_level]
145    
146     /* because exp_obj sum to make the total score,
147     * we cannot allow that sum to exceed the maximum
148     * amount of experience a player can gain. Thus
149     * we define MAX_EXP_IN_OBJ. It is important to try
150     * to make the value of MAX_EXP_CAT close to the
151     * actual number of experience objects in the game,
152     * otherwise the maximum level in any experience
153     * category could be quite low. To help the situation
154     * out a little I added 10 more levels, and jacked
155     * up the last level experience value. Its out of
156     * line with progression of previous levels, so
157     * if more levels are desired, this should be fixed.
158     * -b.t.
159     */
160    
161 root 1.9 #define MAX_EXP_IN_OBJ levels[settings.max_level]/(MAX_EXP_CAT - 1)
162 elmex 1.1
163     #ifndef WIN32
164     extern uint64 *levels;
165     #else
166     extern sint64 *levels;
167     #endif
168    
169     #define MAX_SAVE_LEVEL 110
170 root 1.9
171 elmex 1.1 /* This no longer needs to be changed anytime the number of
172     * levels is increased - rather, did_make_save will do the
173     * right thing and always use range within this table.
174     * for safety, savethrow should not be accessed directly anymore,
175     * and instead did_make_save should be used instead.
176     */
177 root 1.9 static const int savethrow[MAX_SAVE_LEVEL + 1] = {
178 elmex 1.1 18,
179 root 1.9 18, 17, 16, 15, 14, 14, 13, 13, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9,
180     9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
181     6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4,
182     4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
183     2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
184     1, 1, 1, 1, 1, 1, 1, 1, 1, 1
185 elmex 1.1 };
186    
187     const char *const attacks[NROFATTACKS] = {
188     "physical", "magical", "fire", "electricity", "cold", "confusion",
189     "acid", "drain", "weaponmagic", "ghosthit", "poison", "slow",
190     "paralyze", "turn undead", "fear", "cancellation", "depletion", "death",
191 root 1.9 "chaos", "counterspell", "god power", "holy power", "blinding", "",
192 elmex 1.1 "life stealing"
193     };
194    
195     static const char *const drain_msg[NUM_STATS] = {
196     "Oh no! You are weakened!",
197     "You're feeling clumsy!",
198     "You feel less healthy",
199     "You suddenly begin to lose your memory!",
200     "Your face gets distorted!",
201 root 1.9 "Watch out, your mind is going!",
202 elmex 1.1 "Your spirit feels drained!"
203     };
204     const char *const restore_msg[NUM_STATS] = {
205     "You feel your strength return.",
206     "You feel your agility return.",
207     "You feel your health return.",
208     "You feel your wisdom return.",
209     "You feel your charisma return.",
210 root 1.9 "You feel your memory return.",
211 elmex 1.1 "You feel your spirits return."
212     };
213     const char *const gain_msg[NUM_STATS] = {
214 root 1.9 "You feel stronger.",
215     "You feel more agile.",
216     "You feel healthy.",
217     "You feel wiser.",
218     "You seem to look better.",
219     "You feel smarter.",
220     "You feel more potent."
221 elmex 1.1 };
222     const char *const lose_msg[NUM_STATS] = {
223 root 1.9 "You feel weaker!",
224     "You feel clumsy!",
225     "You feel less healthy!",
226     "You lose some of your memory!",
227     "You look ugly!",
228     "You feel stupid!",
229     "You feel less potent!"
230 elmex 1.1 };
231    
232     const char *const statname[NUM_STATS] = {
233 root 1.9 "strength", "dexterity", "constitution", "wisdom", "charisma", "intelligence", "power"
234 elmex 1.1 };
235    
236     const char *const short_stat_name[NUM_STATS] = {
237 root 1.9 "Str", "Dex", "Con", "Wis", "Cha", "Int", "Pow"
238 elmex 1.1 };
239    
240     /*
241     * sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on
242     * what attr is (STR to POW).
243     */
244    
245     void
246 root 1.9 set_attr_value (living * stats, int attr, sint8 value)
247     {
248     switch (attr)
249     {
250 root 1.10 case STR:
251     stats->Str = value;
252     break;
253     case DEX:
254     stats->Dex = value;
255     break;
256     case CON:
257     stats->Con = value;
258     break;
259     case WIS:
260     stats->Wis = value;
261     break;
262     case POW:
263     stats->Pow = value;
264     break;
265     case CHA:
266     stats->Cha = value;
267     break;
268     case INT:
269     stats->Int = value;
270     break;
271 root 1.9 }
272 elmex 1.1 }
273    
274     /*
275     * Like set_attr_value(), but instead the value (which can be negative)
276     * is added to the specified stat.
277     */
278    
279     void
280 root 1.9 change_attr_value (living * stats, int attr, sint8 value)
281     {
282     if (value == 0)
283     return;
284     switch (attr)
285     {
286 root 1.10 case STR:
287     stats->Str += value;
288     break;
289     case DEX:
290     stats->Dex += value;
291     break;
292     case CON:
293     stats->Con += value;
294     break;
295     case WIS:
296     stats->Wis += value;
297     break;
298     case POW:
299     stats->Pow += value;
300     break;
301     case CHA:
302     stats->Cha += value;
303     break;
304     case INT:
305     stats->Int += value;
306     break;
307     default:
308     LOG (llevError, "Invalid attribute in change_attr_value: %d\n", attr);
309 root 1.9 }
310 elmex 1.1 }
311    
312     /*
313     * returns the specified stat. See also set_attr_value().
314     */
315    
316     sint8
317 root 1.9 get_attr_value (const living * stats, int attr)
318     {
319     switch (attr)
320     {
321 root 1.10 case STR:
322     return (stats->Str);
323     case DEX:
324     return (stats->Dex);
325     case CON:
326     return (stats->Con);
327     case WIS:
328     return (stats->Wis);
329     case CHA:
330     return (stats->Cha);
331     case INT:
332     return (stats->Int);
333     case POW:
334     return (stats->Pow);
335 root 1.9 }
336 elmex 1.1 return 0;
337     }
338    
339     /*
340     * Ensures that all stats (str/dex/con/wis/cha/int) are within the
341     * 1-30 stat limit.
342     */
343    
344 root 1.9 void
345     check_stat_bounds (living * stats)
346     {
347     int i, v;
348    
349     for (i = 0; i < NUM_STATS; i++)
350     if ((v = get_attr_value (stats, i)) > MAX_STAT)
351     set_attr_value (stats, i, MAX_STAT);
352     else if (v < MIN_STAT)
353     set_attr_value (stats, i, MIN_STAT);
354 elmex 1.1 }
355    
356     #define ORIG_S(xyz,abc) (op->contr->orig_stats.abc)
357    
358     /* Rather than having a whole bunch of if (flag) new_draw.. else new_draw,
359     * make this macro to clean those up. Not usuable outside change_abil
360     * function since some of the values passed to new_draw_info are hardcoded.
361     */
362     #define DIFF_MSG(flag, msg1, msg2) \
363     new_draw_info(NDI_UNIQUE, 0, op, (flag>0)?msg1:msg2);
364    
365     /* return 1 if we sucessfully changed a stat, 0 if nothing was changed. */
366 root 1.9
367 elmex 1.1 /* flag is set to 1 if we are applying the object, -1 if we are removing
368     * the object.
369     * It is the calling functions responsibilty to check to see if the object
370     * can be applied or not.
371     * The main purpose of calling this function is the messages that are
372     * displayed - fix_player should really always be called after this when
373     * removing an object - that is because it is impossible to know if some object
374     * is the only source of an attacktype or spell attunement, so this function
375     * will clear the bits, but the player may still have some other object
376     * that gives them that ability.
377     */
378 root 1.9 int
379     change_abil (object *op, object *tmp)
380     {
381     int flag = QUERY_FLAG (tmp, FLAG_APPLIED) ? 1 : -1, i, j, success = 0;
382     char message[MAX_BUF];
383     int potion_max = 0;
384    
385     /* remember what object was like before it was changed. note that
386     * refop is a local copy of op only to be used for detecting changes
387     * found by fix_player. refop is not a real object
388     */
389     object_pod refop = *op;
390    
391     if (op->type == PLAYER)
392     {
393     if (tmp->type == POTION)
394     {
395     potion_max = 1;
396     for (j = 0; j < NUM_STATS; j++)
397     {
398     int nstat, ostat;
399    
400     ostat = get_attr_value (&(op->contr->orig_stats), j);
401     i = get_attr_value (&(tmp->stats), j);
402    
403     /* nstat is what the stat will be after use of the potion */
404     nstat = flag * i + ostat;
405    
406     /* Do some bounds checking. While I don't think any
407     * potions do so right now, there is the potential for potions
408     * that adjust that stat by more than one point, so we need
409     * to allow for that.
410     */
411     if (nstat < 1 && i * flag < 0)
412     nstat = 1;
413     else if (nstat > 20 + get_attr_value (&(op->arch->clone.stats), j))
414     {
415     nstat = 20 + get_attr_value (&(op->arch->clone.stats), j);
416 root 1.3 }
417 root 1.9 if (nstat != ostat)
418     {
419     set_attr_value (&(op->contr->orig_stats), j, nstat);
420     potion_max = 0;
421 root 1.3 }
422 root 1.9 else if (i)
423     {
424     /* potion is useless - player has already hit the natural maximum */
425     potion_max = 1;
426 root 1.3 }
427     }
428 root 1.9 /* This section of code ups the characters normal stats also. I am not
429     * sure if this is strictly necessary, being that fix_player probably
430     * recalculates this anyway.
431     */
432     for (j = 0; j < NUM_STATS; j++)
433     change_attr_value (&(op->stats), j, flag * get_attr_value (&(tmp->stats), j));
434     check_stat_bounds (&(op->stats));
435     } /* end of potion handling code */
436     }
437    
438     /* reset attributes that fix_player doesn't reset since it doesn't search
439     * everything to set
440     */
441     if (flag == -1)
442     {
443     op->attacktype &= ~tmp->attacktype;
444     op->path_attuned &= ~tmp->path_attuned;
445     op->path_repelled &= ~tmp->path_repelled;
446     op->path_denied &= ~tmp->path_denied;
447     /* Presuming here that creatures only have move_type,
448     * and not the other move_ fields.
449     */
450     op->move_type &= ~tmp->move_type;
451 elmex 1.1 }
452    
453 root 1.9 /* call fix_player since op object could have whatever attribute due
454     * to multiple items. if fix_player always has to be called after
455     * change_ability then might as well call it from here
456     */
457     fix_player (op);
458    
459     /* Fix player won't add the bows ability to the player, so don't
460     * print out message if this is a bow.
461     */
462     if (tmp->attacktype & AT_CONFUSION && tmp->type != BOW)
463     {
464     success = 1;
465     DIFF_MSG (flag, "Your hands begin to glow red.", "Your hands stop glowing red.");
466     }
467     if (QUERY_FLAG (op, FLAG_LIFESAVE) != QUERY_FLAG (&refop, FLAG_LIFESAVE))
468     {
469     success = 1;
470     DIFF_MSG (flag, "You feel very protected.", "You don't feel protected anymore.");
471     }
472     if (QUERY_FLAG (op, FLAG_REFL_MISSILE) != QUERY_FLAG (&refop, FLAG_REFL_MISSILE))
473     {
474     success = 1;
475     DIFF_MSG (flag, "A magic force shimmers around you.", "The magic force fades away.");
476     }
477     if (QUERY_FLAG (op, FLAG_REFL_SPELL) != QUERY_FLAG (&refop, FLAG_REFL_SPELL))
478     {
479     success = 1;
480     DIFF_MSG (flag, "You feel more safe now, somehow.", "Suddenly you feel less safe, somehow.");
481     }
482     /* movement type has changed. We don't care about cases where
483     * user has multiple items giving the same type appled like we
484     * used to - that is more work than what we gain, plus messages
485     * can be misleading (a little higher could be miscontrued from
486     * from fly high)
487     */
488     if (tmp->move_type && op->move_type != refop.move_type)
489     {
490     success = 1;
491 elmex 1.1
492 root 1.9 /* MOVE_FLY_HIGH trumps MOVE_FLY_LOW - changing your move_fly_low
493     * status doesn't make a difference if you are flying high
494     */
495     if (tmp->move_type & MOVE_FLY_LOW && !(op->move_type & MOVE_FLY_HIGH))
496     {
497     DIFF_MSG (flag, "You start to float in the air!.", "You float down to the ground.");
498 root 1.3 }
499    
500 root 1.9 if (tmp->move_type & MOVE_FLY_HIGH)
501     {
502     /* double conditional - second case covers if you have move_fly_low -
503     * in that case, you don't actually land
504     */
505     DIFF_MSG (flag, "You soar into the air air!.",
506     (op->move_type & MOVE_FLY_LOW ? "You fly lower in the air" : "You float down to the ground."));
507 root 1.3 }
508 root 1.9 if (tmp->move_type & MOVE_SWIM)
509     DIFF_MSG (flag, "You feel ready for a swim", "You no longer feel like swimming");
510 elmex 1.1
511 root 1.9 /* Changing move status may mean you are affected by things you weren't before */
512     check_move_on (op, op);
513 elmex 1.1 }
514    
515 root 1.9 /* becoming UNDEAD... a special treatment for this flag. Only those not
516     * originally undead may change their status
517     */
518     if (!QUERY_FLAG (&op->arch->clone, FLAG_UNDEAD))
519     if (QUERY_FLAG (op, FLAG_UNDEAD) != QUERY_FLAG (&refop, FLAG_UNDEAD))
520     {
521     success = 1;
522     if (flag > 0)
523     {
524     op->race = "undead";
525     new_draw_info (NDI_UNIQUE, 0, op, "Your lifeforce drains away!");
526     }
527     else
528     {
529     op->race = op->arch->clone.race;
530     new_draw_info (NDI_UNIQUE, 0, op, "Your lifeforce returns!");
531     }
532     }
533 elmex 1.1
534 root 1.9 if (QUERY_FLAG (op, FLAG_STEALTH) != QUERY_FLAG (&refop, FLAG_STEALTH))
535     {
536     success = 1;
537     DIFF_MSG (flag, "You walk more quietly.", "You walk more noisily.");
538 elmex 1.1 }
539 root 1.9 if (QUERY_FLAG (op, FLAG_MAKE_INVIS) != QUERY_FLAG (&refop, FLAG_MAKE_INVIS))
540     {
541     success = 1;
542     DIFF_MSG (flag, "You become transparent.", "You can see yourself.");
543 elmex 1.1 }
544 root 1.9 /* blinded you can tell if more blinded since blinded player has minimal
545     * vision
546     */
547     if (QUERY_FLAG (tmp, FLAG_BLIND))
548     {
549     success = 1;
550     if (flag > 0)
551     {
552     if (QUERY_FLAG (op, FLAG_WIZ))
553     new_draw_info (NDI_UNIQUE, 0, op, "Your mortal self is blinded.");
554     else
555     {
556     new_draw_info (NDI_UNIQUE, 0, op, "You are blinded.");
557     SET_FLAG (op, FLAG_BLIND);
558     if (op->type == PLAYER)
559     op->contr->do_los = 1;
560 root 1.3 }
561 root 1.9 }
562     else
563     {
564     if (QUERY_FLAG (op, FLAG_WIZ))
565     new_draw_info (NDI_UNIQUE, 0, op, "Your mortal self can now see again.");
566     else
567     {
568     new_draw_info (NDI_UNIQUE, 0, op, "Your vision returns.");
569     CLEAR_FLAG (op, FLAG_BLIND);
570     if (op->type == PLAYER)
571     op->contr->do_los = 1;
572 root 1.3 }
573     }
574 elmex 1.1 }
575    
576 root 1.9 if (QUERY_FLAG (op, FLAG_SEE_IN_DARK) != QUERY_FLAG (&refop, FLAG_SEE_IN_DARK))
577     {
578     success = 1;
579     if (op->type == PLAYER)
580     op->contr->do_los = 1;
581     DIFF_MSG (flag, "Your vision is better in the dark.", "You see less well in the dark.");
582 elmex 1.1 }
583    
584 root 1.9 if (QUERY_FLAG (op, FLAG_XRAYS) != QUERY_FLAG (&refop, FLAG_XRAYS))
585     {
586     success = 1;
587     if (flag > 0)
588     {
589     if (QUERY_FLAG (op, FLAG_WIZ))
590     new_draw_info (NDI_UNIQUE, 0, op, "Your vision becomes a little clearer.");
591     else
592     {
593     new_draw_info (NDI_UNIQUE, 0, op, "Everything becomes transparent.");
594     if (op->type == PLAYER)
595     op->contr->do_los = 1;
596 root 1.3 }
597 root 1.9 }
598     else
599     {
600     if (QUERY_FLAG (op, FLAG_WIZ))
601     new_draw_info (NDI_UNIQUE, 0, op, "Your vision becomes a bit out of focus.");
602     else
603     {
604     new_draw_info (NDI_UNIQUE, 0, op, "Everything suddenly looks very solid.");
605     if (op->type == PLAYER)
606     op->contr->do_los = 1;
607 root 1.3 }
608     }
609 elmex 1.1 }
610    
611 root 1.9 if (tmp->stats.luck)
612     {
613     success = 1;
614     DIFF_MSG (flag * tmp->stats.luck, "You feel more lucky.", "You feel less lucky.");
615 elmex 1.1 }
616    
617 root 1.9 if (tmp->stats.hp && op->type == PLAYER)
618     {
619     success = 1;
620     DIFF_MSG (flag * tmp->stats.hp, "You feel much more healthy!", "You feel much less healthy!");
621 elmex 1.1 }
622    
623 root 1.9 if (tmp->stats.sp && op->type == PLAYER && tmp->type != SKILL)
624     {
625     success = 1;
626     DIFF_MSG (flag * tmp->stats.sp, "You feel one with the powers of magic!", "You suddenly feel very mundane.");
627 elmex 1.1 }
628    
629 root 1.9 /* for the future when artifacts set this -b.t. */
630     if (tmp->stats.grace && op->type == PLAYER)
631     {
632     success = 1;
633     DIFF_MSG (flag * tmp->stats.grace, "You feel closer to your god!", "You suddenly feel less holy.");
634 elmex 1.1 }
635    
636 root 1.9 if (tmp->stats.food && op->type == PLAYER)
637     {
638     success = 1;
639     DIFF_MSG (flag * tmp->stats.food, "You feel your digestion slowing down.", "You feel your digestion speeding up.");
640 elmex 1.1 }
641    
642 root 1.9 /* Messages for changed resistance */
643     for (i = 0; i < NROFATTACKS; i++)
644     {
645     if (i == ATNR_PHYSICAL)
646     continue; /* Don't display about armour */
647    
648     if (op->resist[i] != refop.resist[i])
649     {
650     success = 1;
651     if (op->resist[i] > refop.resist[i])
652     sprintf (message, "Your resistance to %s rises to %d%%.", change_resist_msg[i], op->resist[i]);
653     else
654     sprintf (message, "Your resistance to %s drops to %d%%.", change_resist_msg[i], op->resist[i]);
655    
656     new_draw_info (NDI_UNIQUE | NDI_BLUE, 0, op, message);
657 root 1.3 }
658 elmex 1.1 }
659    
660 root 1.9 if (tmp->type != EXPERIENCE && !potion_max)
661     {
662     for (j = 0; j < NUM_STATS; j++)
663     {
664     if ((i = get_attr_value (&(tmp->stats), j)) != 0)
665     {
666     success = 1;
667     DIFF_MSG (i * flag, gain_msg[j], lose_msg[j]);
668 root 1.3 }
669     }
670 elmex 1.1 }
671 root 1.9 return success;
672 elmex 1.1 }
673    
674     /*
675     * Stat draining by Vick 930307
676     * (Feeling evil, I made it work as well now. -Frank 8)
677     */
678    
679 root 1.9 void
680     drain_stat (object *op)
681     {
682     drain_specific_stat (op, RANDOM () % NUM_STATS);
683 elmex 1.1 }
684    
685 root 1.9 void
686     drain_specific_stat (object *op, int deplete_stats)
687     {
688 elmex 1.1 object *tmp;
689     archetype *at;
690    
691 root 1.9 at = find_archetype (ARCH_DEPLETION);
692     if (!at)
693     {
694     LOG (llevError, "Couldn't find archetype depletion.\n");
695     return;
696     }
697     else
698     {
699     tmp = present_arch_in_ob (at, op);
700     if (!tmp)
701     {
702     tmp = arch_to_object (at);
703     tmp = insert_ob_in_ob (tmp, op);
704     SET_FLAG (tmp, FLAG_APPLIED);
705     }
706     }
707    
708     new_draw_info (NDI_UNIQUE, 0, op, drain_msg[deplete_stats]);
709     change_attr_value (&tmp->stats, deplete_stats, -1);
710     fix_player (op);
711 elmex 1.1 }
712    
713     /*
714     * A value of 0 indicates timeout, otherwise change the luck of the object.
715     * via an applied bad_luck object.
716     */
717    
718 root 1.9 void
719     change_luck (object *op, int value)
720     {
721 elmex 1.1 object *tmp;
722     archetype *at;
723     int new_luck;
724    
725 root 1.9 at = find_archetype ("luck");
726 elmex 1.1 if (!at)
727 root 1.9 LOG (llevError, "Couldn't find archetype luck.\n");
728     else
729     {
730     tmp = present_arch_in_ob (at, op);
731     if (!tmp)
732     {
733     if (!value)
734     return;
735     tmp = arch_to_object (at);
736     tmp = insert_ob_in_ob (tmp, op);
737     SET_FLAG (tmp, FLAG_APPLIED);
738     }
739     if (value)
740     {
741     /* Limit the luck value of the bad luck object to +/-100. This
742     * (arbitrary) value prevents overflows (both in the bad luck object and
743     * in op itself).
744     */
745     new_luck = tmp->stats.luck + value;
746     if (new_luck >= -100 && new_luck <= 100)
747     {
748     op->stats.luck += value;
749     tmp->stats.luck = new_luck;
750     }
751     }
752     else
753     {
754     if (!tmp->stats.luck)
755     {
756     return;
757     }
758     /* Randomly change the players luck. Basically, we move it
759     * back neutral (if greater>0, subtract, otherwise add)
760     */
761     if (RANDOM () % (FABS (tmp->stats.luck)) >= RANDOM () % 30)
762     {
763     int diff = tmp->stats.luck > 0 ? -1 : 1;
764    
765     op->stats.luck += diff;
766     tmp->stats.luck += diff;
767     }
768     }
769 elmex 1.1 }
770     }
771    
772     /*
773     * Subtracts stat-bonuses given by the class which the player has chosen.
774     */
775    
776 root 1.9 void
777     remove_statbonus (object *op)
778     {
779 elmex 1.1 op->stats.Str -= op->arch->clone.stats.Str;
780     op->stats.Dex -= op->arch->clone.stats.Dex;
781     op->stats.Con -= op->arch->clone.stats.Con;
782     op->stats.Wis -= op->arch->clone.stats.Wis;
783     op->stats.Pow -= op->arch->clone.stats.Pow;
784     op->stats.Cha -= op->arch->clone.stats.Cha;
785     op->stats.Int -= op->arch->clone.stats.Int;
786     op->contr->orig_stats.Str -= op->arch->clone.stats.Str;
787     op->contr->orig_stats.Dex -= op->arch->clone.stats.Dex;
788     op->contr->orig_stats.Con -= op->arch->clone.stats.Con;
789     op->contr->orig_stats.Wis -= op->arch->clone.stats.Wis;
790     op->contr->orig_stats.Pow -= op->arch->clone.stats.Pow;
791     op->contr->orig_stats.Cha -= op->arch->clone.stats.Cha;
792     op->contr->orig_stats.Int -= op->arch->clone.stats.Int;
793     }
794    
795     /*
796     * Adds stat-bonuses given by the class which the player has chosen.
797     */
798    
799 root 1.9 void
800     add_statbonus (object *op)
801     {
802 elmex 1.1 op->stats.Str += op->arch->clone.stats.Str;
803     op->stats.Dex += op->arch->clone.stats.Dex;
804     op->stats.Con += op->arch->clone.stats.Con;
805     op->stats.Wis += op->arch->clone.stats.Wis;
806     op->stats.Pow += op->arch->clone.stats.Pow;
807     op->stats.Cha += op->arch->clone.stats.Cha;
808     op->stats.Int += op->arch->clone.stats.Int;
809     op->contr->orig_stats.Str += op->arch->clone.stats.Str;
810     op->contr->orig_stats.Dex += op->arch->clone.stats.Dex;
811     op->contr->orig_stats.Con += op->arch->clone.stats.Con;
812     op->contr->orig_stats.Wis += op->arch->clone.stats.Wis;
813     op->contr->orig_stats.Pow += op->arch->clone.stats.Pow;
814     op->contr->orig_stats.Cha += op->arch->clone.stats.Cha;
815     op->contr->orig_stats.Int += op->arch->clone.stats.Int;
816     }
817    
818     /*
819     * Updates all abilities given by applied objects in the inventory
820     * of the given object. Note: This function works for both monsters
821     * and players; the "player" in the name is purely an archaic inheritance.
822     * This functions starts from base values (archetype or player object)
823     * and then adjusts them according to what the player has equipped.
824     */
825 root 1.9
826 elmex 1.1 /* July 95 - inserted stuff to handle new skills/exp system - b.t.
827     spell system split, grace points now added to system --peterm
828     */
829    
830 root 1.9 void
831     fix_player (object *op)
832     {
833     int i, j;
834     float f, max = 9, added_speed = 0, bonus_speed = 0, sp_tmp, speed_reduce_from_disease = 1;
835     int weapon_weight = 0, weapon_speed = 0;
836     int best_wc = 0, best_ac = 0, wc = 0, ac = 0;
837     int prot[NROFATTACKS], vuln[NROFATTACKS], potion_resist[NROFATTACKS];
838     object *grace_obj = NULL, *mana_obj = NULL, *wc_obj = NULL, *tmp;
839    
840     /* First task is to clear all the values back to their original values */
841     if (op->type == PLAYER)
842     {
843     for (i = 0; i < NUM_STATS; i++)
844     {
845     set_attr_value (&(op->stats), i, get_attr_value (&(op->contr->orig_stats), i));
846     }
847     if (settings.spell_encumbrance == TRUE)
848     op->contr->encumbrance = 0;
849    
850     op->attacktype = 0;
851     op->contr->digestion = 0;
852     op->contr->gen_hp = 0;
853     op->contr->gen_sp = 0;
854     op->contr->gen_grace = 0;
855     op->contr->gen_sp_armour = 10;
856     op->contr->item_power = 0;
857    
858     /* Don't clobber all the range_ values. range_golem otherwise
859     * gets reset for no good reason, and we don't want to reset
860     * range_magic (what spell is readied). These three below
861     * well get filled in based on what the player has equipped.
862     */
863     op->contr->ranges[range_bow] = NULL;
864     op->contr->ranges[range_misc] = NULL;
865     op->contr->ranges[range_skill] = NULL;
866     }
867     memcpy (op->body_used, op->body_info, sizeof (op->body_info));
868    
869     op->slaying = 0;
870    
871     if (!QUERY_FLAG (op, FLAG_WIZ))
872     {
873     CLEAR_FLAG (op, FLAG_XRAYS);
874     CLEAR_FLAG (op, FLAG_MAKE_INVIS);
875     }
876    
877     CLEAR_FLAG (op, FLAG_LIFESAVE);
878     CLEAR_FLAG (op, FLAG_STEALTH);
879     CLEAR_FLAG (op, FLAG_BLIND);
880     if (!QUERY_FLAG (&op->arch->clone, FLAG_REFL_SPELL))
881     CLEAR_FLAG (op, FLAG_REFL_SPELL);
882     if (!QUERY_FLAG (&op->arch->clone, FLAG_REFL_MISSILE))
883     CLEAR_FLAG (op, FLAG_REFL_MISSILE);
884     if (!QUERY_FLAG (&op->arch->clone, FLAG_UNDEAD))
885     CLEAR_FLAG (op, FLAG_UNDEAD);
886     if (!QUERY_FLAG (&op->arch->clone, FLAG_SEE_IN_DARK))
887     CLEAR_FLAG (op, FLAG_SEE_IN_DARK);
888    
889     op->path_attuned = op->arch->clone.path_attuned;
890     op->path_repelled = op->arch->clone.path_repelled;
891     op->path_denied = op->arch->clone.path_denied;
892     op->glow_radius = op->arch->clone.glow_radius;
893     op->move_type = op->arch->clone.move_type;
894     op->chosen_skill = NULL;
895    
896     /* initializing resistances from the values in player/monster's
897     * archetype clone
898     */
899     memcpy (&op->resist, &op->arch->clone.resist, sizeof (op->resist));
900    
901     for (i = 0; i < NROFATTACKS; i++)
902     {
903     if (op->resist[i] > 0)
904     prot[i] = op->resist[i], vuln[i] = 0;
905     else
906     vuln[i] = -(op->resist[i]), prot[i] = 0;
907     potion_resist[i] = 0;
908     }
909    
910     wc = op->arch->clone.stats.wc;
911     op->stats.dam = op->arch->clone.stats.dam;
912    
913     /* for players which cannot use armour, they gain AC -1 per 3 levels,
914     * plus a small amount of physical resist, those poor suckers. ;)
915     * the fact that maxlevel is factored in could be considered sort of bogus -
916     * we should probably give them some bonus and cap it off - otherwise,
917     * basically, if a server updates its max level, these playes may find
918     * that their protection from physical goes down
919     */
920     if (!QUERY_FLAG (op, FLAG_USE_ARMOUR) && op->type == PLAYER)
921     {
922     ac = MAX (-10, op->arch->clone.stats.ac - op->level / 3);
923     prot[ATNR_PHYSICAL] += ((100 - prot[AT_PHYSICAL]) * (80 * op->level / settings.max_level)) / 100;
924 elmex 1.1 }
925 root 1.9 else
926     ac = op->arch->clone.stats.ac;
927    
928     op->stats.luck = op->arch->clone.stats.luck;
929     op->speed = op->arch->clone.speed;
930    
931     /* OK - we've reset most all the objects attributes to sane values.
932     * now go through and make adjustments for what the player has equipped.
933     */
934    
935     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
936     {
937     /* See note in map.c:update_position about making this additive
938     * since light sources are never applied, need to put check here.
939     */
940     if (tmp->glow_radius > op->glow_radius)
941     op->glow_radius = tmp->glow_radius;
942 root 1.3
943 root 1.9 /* This happens because apply_potion calls change_abil with the potion
944     * applied so we can tell the player what chagned. But change_abil
945     * then calls this function.
946     */
947     if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type == POTION)
948     {
949     continue;
950 root 1.3 }
951    
952 root 1.9 /* For some things, we don't care what is equipped */
953     if (tmp->type == SKILL)
954     {
955     /* Want to take the highest skill here. */
956     if (IS_MANA_SKILL (tmp->subtype))
957     {
958     if (!mana_obj)
959     mana_obj = tmp;
960     else if (tmp->level > mana_obj->level)
961     mana_obj = tmp;
962     }
963     if (IS_GRACE_SKILL (tmp->subtype))
964     {
965     if (!grace_obj)
966     grace_obj = tmp;
967     else if (tmp->level > grace_obj->level)
968     grace_obj = tmp;
969 root 1.3 }
970     }
971    
972 root 1.9 /* Container objects are not meant to adjust a players, but other applied
973     * objects need to make adjustments.
974     * This block should handle all player specific changes
975     * The check for Praying is a bit of a hack - god given bonuses are put
976     * in the praying skill, and the player should always get those.
977     * It also means we need to put in additional checks for applied below,
978     * because the skill shouldn't count against body positions being used
979     * up, etc.
980     */
981     if ((QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type != CONTAINER && tmp->type != CLOSE_CON) ||
982     (tmp->type == SKILL && tmp->subtype == SK_PRAYING))
983     {
984     if (op->type == PLAYER)
985     {
986     if (tmp->type == BOW)
987     op->contr->ranges[range_bow] = tmp;
988    
989     if (tmp->type == WAND || tmp->type == ROD || tmp->type == HORN)
990     op->contr->ranges[range_misc] = tmp;
991    
992     for (i = 0; i < NUM_STATS; i++)
993     change_attr_value (&(op->stats), i, get_attr_value (&(tmp->stats), i));
994    
995     /* these are the items that currently can change digestion, regeneration,
996     * spell point recovery and mana point recovery. Seems sort of an arbitary
997     * list, but other items store other info into stats array.
998     */
999     if ((tmp->type == EXPERIENCE) || (tmp->type == WEAPON) ||
1000     (tmp->type == ARMOUR) || (tmp->type == HELMET) ||
1001     (tmp->type == SHIELD) || (tmp->type == RING) ||
1002     (tmp->type == BOOTS) || (tmp->type == GLOVES) ||
1003     (tmp->type == AMULET) || (tmp->type == GIRDLE) ||
1004     (tmp->type == BRACERS) || (tmp->type == CLOAK) || (tmp->type == DISEASE) || (tmp->type == FORCE) || (tmp->type == SKILL))
1005     {
1006     op->contr->digestion += tmp->stats.food;
1007     op->contr->gen_hp += tmp->stats.hp;
1008     op->contr->gen_sp += tmp->stats.sp;
1009     op->contr->gen_grace += tmp->stats.grace;
1010     op->contr->gen_sp_armour += tmp->gen_sp_armour;
1011     op->contr->item_power += tmp->item_power;
1012 root 1.3 }
1013 root 1.9 } /* if this is a player */
1014 root 1.3
1015 root 1.9 /* Update slots used for items */
1016     if (QUERY_FLAG (tmp, FLAG_APPLIED))
1017     {
1018     for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1019     op->body_used[i] += tmp->body_info[i];
1020 root 1.3 }
1021    
1022 root 1.9 if (tmp->type == SYMPTOM)
1023     {
1024     speed_reduce_from_disease = tmp->last_sp / 100.0;
1025     if (speed_reduce_from_disease == 0)
1026     speed_reduce_from_disease = 1;
1027 root 1.3 }
1028    
1029 root 1.9 /* Pos. and neg. protections are counted seperate (-> pro/vuln).
1030     * (Negative protections are calculated extactly like positive.)
1031     * Resistance from potions are treated special as well. If there's
1032     * more than one potion-effect, the bigger prot.-value is taken.
1033     */
1034     if (tmp->type != POTION)
1035     {
1036     for (i = 0; i < NROFATTACKS; i++)
1037     {
1038     /* Potential for cursed potions, in which case we just can use
1039     * a straight MAX, as potion_resist is initialized to zero.
1040     */
1041     if (tmp->type == POTION_EFFECT)
1042     {
1043     if (potion_resist[i])
1044     potion_resist[i] = MAX (potion_resist[i], tmp->resist[i]);
1045     else
1046     potion_resist[i] = tmp->resist[i];
1047 root 1.3 }
1048 root 1.9 else if (tmp->resist[i] > 0)
1049     prot[i] += ((100 - prot[i]) * tmp->resist[i]) / 100;
1050     else if (tmp->resist[i] < 0)
1051     vuln[i] += ((100 - vuln[i]) * (-tmp->resist[i])) / 100;
1052     }
1053     }
1054    
1055     /* There may be other things that should not adjust the attacktype */
1056     if (tmp->type != BOW && tmp->type != SYMPTOM)
1057     op->attacktype |= tmp->attacktype;
1058    
1059     op->path_attuned |= tmp->path_attuned;
1060     op->path_repelled |= tmp->path_repelled;
1061     op->path_denied |= tmp->path_denied;
1062     op->stats.luck += tmp->stats.luck;
1063     op->move_type |= tmp->move_type;
1064    
1065     if (QUERY_FLAG (tmp, FLAG_LIFESAVE))
1066     SET_FLAG (op, FLAG_LIFESAVE);
1067     if (QUERY_FLAG (tmp, FLAG_REFL_SPELL))
1068     SET_FLAG (op, FLAG_REFL_SPELL);
1069     if (QUERY_FLAG (tmp, FLAG_REFL_MISSILE))
1070     SET_FLAG (op, FLAG_REFL_MISSILE);
1071     if (QUERY_FLAG (tmp, FLAG_STEALTH))
1072     SET_FLAG (op, FLAG_STEALTH);
1073     if (QUERY_FLAG (tmp, FLAG_XRAYS))
1074     SET_FLAG (op, FLAG_XRAYS);
1075     if (QUERY_FLAG (tmp, FLAG_BLIND))
1076     SET_FLAG (op, FLAG_BLIND);
1077     if (QUERY_FLAG (tmp, FLAG_SEE_IN_DARK))
1078     SET_FLAG (op, FLAG_SEE_IN_DARK);
1079    
1080     if (QUERY_FLAG (tmp, FLAG_UNDEAD) && !QUERY_FLAG (&op->arch->clone, FLAG_UNDEAD))
1081     SET_FLAG (op, FLAG_UNDEAD);
1082    
1083     if (QUERY_FLAG (tmp, FLAG_MAKE_INVIS))
1084     {
1085     SET_FLAG (op, FLAG_MAKE_INVIS);
1086     op->invisible = 1;
1087     }
1088    
1089     if (tmp->stats.exp && tmp->type != SKILL)
1090     {
1091     if (tmp->stats.exp > 0)
1092     {
1093     added_speed += (float) tmp->stats.exp / 3.0;
1094     bonus_speed += 1.0 + (float) tmp->stats.exp / 3.0;
1095 root 1.3 }
1096 root 1.9 else
1097     added_speed += (float) tmp->stats.exp;
1098 root 1.3 }
1099    
1100 root 1.9 switch (tmp->type)
1101     {
1102 root 1.10 /* skills modifying the character -b.t. */
1103     /* for all skills and skill granting objects */
1104     case SKILL:
1105     if (!QUERY_FLAG (tmp, FLAG_APPLIED))
1106     break;
1107 root 1.3
1108 root 1.10 if (IS_COMBAT_SKILL (tmp->subtype))
1109     wc_obj = tmp;
1110 root 1.3
1111 root 1.10 if (op->chosen_skill)
1112     LOG (llevDebug, "fix_player, op %s has multiple skills applied\n", &op->name);
1113    
1114     op->chosen_skill = tmp;
1115    
1116     if (tmp->stats.dam > 0)
1117     { /* skill is a 'weapon' */
1118     if (!QUERY_FLAG (op, FLAG_READY_WEAPON))
1119     weapon_speed = (int) WEAPON_SPEED (tmp);
1120     if (weapon_speed < 0)
1121     weapon_speed = 0;
1122     weapon_weight = tmp->weight;
1123     op->stats.dam += tmp->stats.dam * (1 + (op->chosen_skill->level / 9));
1124     if (tmp->magic)
1125     op->stats.dam += tmp->magic;
1126     }
1127 root 1.3
1128 root 1.10 if (tmp->stats.wc)
1129     wc -= (tmp->stats.wc + tmp->magic);
1130 root 1.3
1131 root 1.10 if (tmp->slaying != NULL)
1132     op->slaying = tmp->slaying;
1133 root 1.9
1134 root 1.10 if (tmp->stats.ac)
1135     ac -= (tmp->stats.ac + tmp->magic);
1136     if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1137     op->contr->encumbrance += (int) 3 *tmp->weight / 1000;
1138 root 1.3
1139 root 1.10 if (op->type == PLAYER)
1140     op->contr->ranges[range_skill] = op;
1141     break;
1142 root 1.3
1143 root 1.10 case SKILL_TOOL:
1144     if (op->chosen_skill)
1145     {
1146     LOG (llevDebug, "fix_player, op %s has multiple skills applied\n", &op->name);
1147     }
1148     op->chosen_skill = tmp;
1149     if (op->type == PLAYER)
1150     op->contr->ranges[range_skill] = op;
1151     break;
1152 root 1.3
1153 root 1.10 case SHIELD:
1154     if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1155     op->contr->encumbrance += (int) tmp->weight / 2000;
1156     case RING:
1157     case AMULET:
1158     case GIRDLE:
1159     case HELMET:
1160     case BOOTS:
1161     case GLOVES:
1162     case CLOAK:
1163     if (tmp->stats.wc)
1164 root 1.9 wc -= (tmp->stats.wc + tmp->magic);
1165 root 1.10 if (tmp->stats.dam)
1166 root 1.9 op->stats.dam += (tmp->stats.dam + tmp->magic);
1167 root 1.10 if (tmp->stats.ac)
1168     ac -= (tmp->stats.ac + tmp->magic);
1169     break;
1170    
1171     case WEAPON:
1172     wc -= (tmp->stats.wc + tmp->magic);
1173     if (tmp->stats.ac && tmp->stats.ac + tmp->magic > 0)
1174     ac -= tmp->stats.ac + tmp->magic;
1175     op->stats.dam += (tmp->stats.dam + tmp->magic);
1176     weapon_weight = tmp->weight;
1177     weapon_speed = ((int) WEAPON_SPEED (tmp) * 2 - tmp->magic) / 2;
1178     if (weapon_speed < 0)
1179     weapon_speed = 0;
1180     op->slaying = tmp->slaying;
1181     /* If there is desire that two handed weapons should do
1182     * extra strength damage, this is where the code should
1183     * go.
1184     */
1185     op->current_weapon = tmp;
1186     if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1187     op->contr->encumbrance += (int) 3 *tmp->weight / 1000;
1188 root 1.9
1189 root 1.10 break;
1190 root 1.9
1191 root 1.10 case ARMOUR: /* Only the best of these three are used: */
1192     if (settings.spell_encumbrance == TRUE && op->type == PLAYER)
1193     op->contr->encumbrance += (int) tmp->weight / 1000;
1194    
1195     case BRACERS:
1196     case FORCE:
1197     if (tmp->stats.wc)
1198     {
1199     if (best_wc < tmp->stats.wc + tmp->magic)
1200     {
1201     wc += best_wc;
1202     best_wc = tmp->stats.wc + tmp->magic;
1203     }
1204     else
1205     wc += tmp->stats.wc + tmp->magic;
1206     }
1207     if (tmp->stats.ac)
1208     {
1209     if (best_ac < tmp->stats.ac + tmp->magic)
1210     {
1211     ac += best_ac; /* Remove last bonus */
1212     best_ac = tmp->stats.ac + tmp->magic;
1213     }
1214     else /* To nullify the below effect */
1215     ac += tmp->stats.ac + tmp->magic;
1216     }
1217     if (tmp->stats.wc)
1218     wc -= (tmp->stats.wc + tmp->magic);
1219     if (tmp->stats.ac)
1220     ac -= (tmp->stats.ac + tmp->magic);
1221     if (ARMOUR_SPEED (tmp) && ARMOUR_SPEED (tmp) / 10.0 < max)
1222     max = ARMOUR_SPEED (tmp) / 10.0;
1223     break;
1224 root 1.9 } /* switch tmp->type */
1225     } /* item is equipped */
1226     } /* for loop of items */
1227    
1228     /* We've gone through all the objects the player has equipped. For many things, we
1229     * have generated intermediate values which we now need to assign.
1230     */
1231    
1232     /* 'total resistance = total protections - total vulnerabilities'.
1233     * If there is an uncursed potion in effect, granting more protection
1234     * than that, we take: 'total resistance = resistance from potion'.
1235     * If there is a cursed (and no uncursed) potion in effect, we take
1236     * 'total resistance = vulnerability from cursed potion'.
1237     */
1238     for (i = 0; i < NROFATTACKS; i++)
1239     {
1240     op->resist[i] = prot[i] - vuln[i];
1241     if (potion_resist[i] && ((potion_resist[i] > op->resist[i]) || (potion_resist[i] < 0)))
1242 root 1.3 op->resist[i] = potion_resist[i];
1243 elmex 1.1 }
1244    
1245 root 1.9 /* Figure out the players sp/mana/hp totals. */
1246     if (op->type == PLAYER)
1247     {
1248     int pl_level;
1249    
1250     check_stat_bounds (&(op->stats));
1251     pl_level = op->level;
1252    
1253     if (pl_level < 1)
1254     pl_level = 1; /* safety, we should always get 1 levels worth of hp! */
1255    
1256     /* You basically get half a con bonus/level. But we do take into account rounding,
1257     * so if your bonus is 7, you still get 7 worth of bonus every 2 levels.
1258     */
1259     for (i = 1, op->stats.maxhp = 0; i <= pl_level && i <= 10; i++)
1260     {
1261     j = op->contr->levhp[i] + con_bonus[op->stats.Con] / 2;
1262     if (i % 2 && con_bonus[op->stats.Con] % 2)
1263     {
1264     if (con_bonus[op->stats.Con] > 0)
1265     j++;
1266     else
1267     j--;
1268     }
1269     op->stats.maxhp += j > 1 ? j : 1; /* always get at least 1 hp/level */
1270     }
1271    
1272     for (i = 11; i <= op->level; i++)
1273     op->stats.maxhp += 2;
1274 elmex 1.1
1275 root 1.9 if (op->stats.hp > op->stats.maxhp)
1276     op->stats.hp = op->stats.maxhp;
1277 elmex 1.1
1278 root 1.9 /* Sp gain is controlled by the level of the player's
1279     * relevant experience object (mana_obj, see above)
1280     */
1281     /* following happen when skills system is not used */
1282     if (!mana_obj)
1283     mana_obj = op;
1284     if (!grace_obj)
1285     grace_obj = op;
1286     /* set maxsp */
1287     if (!mana_obj || !mana_obj->level || op->type != PLAYER)
1288     mana_obj = op;
1289    
1290     if (mana_obj == op && op->type == PLAYER)
1291     {
1292     op->stats.maxsp = 1;
1293     }
1294     else
1295     {
1296     sp_tmp = 0.0;
1297     for (i = 1; i <= mana_obj->level && i <= 10; i++)
1298     {
1299     float stmp;
1300    
1301     /* Got some extra bonus at first level */
1302     if (i < 2)
1303     {
1304     stmp = op->contr->levsp[i] + ((2.0 * (float) sp_bonus[op->stats.Pow] + (float) sp_bonus[op->stats.Int]) / 6.0);
1305     }
1306     else
1307     {
1308     stmp = (float) op->contr->levsp[i] + (2.0 * (float) sp_bonus[op->stats.Pow] + (float) sp_bonus[op->stats.Int]) / 12.0;
1309 root 1.3 }
1310 root 1.9 if (stmp < 1.0)
1311     stmp = 1.0;
1312     sp_tmp += stmp;
1313 root 1.3 }
1314 root 1.9 op->stats.maxsp = (int) sp_tmp;
1315 root 1.3
1316 root 1.9 for (i = 11; i <= mana_obj->level; i++)
1317     op->stats.maxsp += 2;
1318 root 1.3 }
1319 root 1.9 /* Characters can get their sp supercharged via rune of transferrance */
1320     if (op->stats.sp > op->stats.maxsp * 2)
1321     op->stats.sp = op->stats.maxsp * 2;
1322    
1323     /* set maxgrace, notice 3-4 lines below it depends on both Wis and Pow */
1324     if (!grace_obj || !grace_obj->level || op->type != PLAYER)
1325     grace_obj = op;
1326    
1327     if (grace_obj == op && op->type == PLAYER)
1328     {
1329     op->stats.maxgrace = 1;
1330     }
1331     else
1332     {
1333     /* store grace in a float - this way, the divisions below don't create
1334     * big jumps when you go from level to level - with int's, it then
1335     * becomes big jumps when the sums of the bonuses jump to the next
1336     * step of 8 - with floats, even fractional ones are useful.
1337     */
1338     sp_tmp = 0.0;
1339     for (i = 1, op->stats.maxgrace = 0; i <= grace_obj->level && i <= 10; i++)
1340     {
1341     float grace_tmp = 0.0;
1342    
1343     /* Got some extra bonus at first level */
1344     if (i < 2)
1345     {
1346     grace_tmp = op->contr->levgrace[i] + (((float) grace_bonus[op->stats.Pow] +
1347     2.0 * (float) grace_bonus[op->stats.Wis]) / 6.0);
1348     }
1349     else
1350     {
1351     grace_tmp = (float) op->contr->levgrace[i]
1352     + ((float) grace_bonus[op->stats.Pow] + 2.0 * (float) grace_bonus[op->stats.Wis]) / 12.0;
1353 root 1.3 }
1354 root 1.9 if (grace_tmp < 1.0)
1355     grace_tmp = 1.0;
1356     sp_tmp += grace_tmp;
1357 root 1.3 }
1358 root 1.9 op->stats.maxgrace = (int) sp_tmp;
1359 root 1.3
1360 root 1.9 /* two grace points per level after 11 */
1361     for (i = 11; i <= grace_obj->level; i++)
1362     op->stats.maxgrace += 2;
1363 root 1.3 }
1364 root 1.9 /* No limit on grace vs maxgrace */
1365 root 1.3
1366 root 1.9 if (op->contr->braced)
1367     {
1368     ac += 2;
1369     wc += 4;
1370 root 1.3 }
1371 root 1.9 else
1372     ac -= dex_bonus[op->stats.Dex];
1373    
1374     /* In new exp/skills system, wc bonuses are related to
1375     * the players level in a relevant exp object (wc_obj)
1376     * not the general player level -b.t.
1377     * I changed this slightly so that wc bonuses are better
1378     * than before. This is to balance out the fact that
1379     * the player no longer gets a personal weapon w/ 1
1380     * improvement every level, now its fighterlevel/5. So
1381     * we give the player a bonus here in wc and dam
1382     * to make up for the change. Note that I left the
1383     * monster bonus the same as before. -b.t.
1384     */
1385    
1386     if (op->type == PLAYER && wc_obj && wc_obj->level > 1)
1387     {
1388     wc -= (wc_obj->level + thaco_bonus[op->stats.Str]);
1389     for (i = 1; i < wc_obj->level; i++)
1390     {
1391     /* addtional wc every 6 levels */
1392     if (!(i % 6))
1393     wc--;
1394     /* addtional dam every 4 levels. */
1395     if (!(i % 4) && (dam_bonus[op->stats.Str] >= 0))
1396     op->stats.dam += (1 + (dam_bonus[op->stats.Str] / 5));
1397     }
1398     }
1399     else
1400     wc -= (op->level + thaco_bonus[op->stats.Str]);
1401    
1402     op->stats.dam += dam_bonus[op->stats.Str];
1403    
1404     if (op->stats.dam < 1)
1405     op->stats.dam = 1;
1406    
1407     op->speed = 1.0 + speed_bonus[op->stats.Dex];
1408     if (settings.search_items && op->contr->search_str[0])
1409     op->speed -= 1;
1410     if (op->attacktype == 0)
1411     op->attacktype = op->arch->clone.attacktype;
1412    
1413     } /* End if player */
1414    
1415     if (added_speed >= 0)
1416     op->speed += added_speed / 10.0;
1417     else /* Something wrong here...: */
1418     op->speed /= (float) (1.0 - added_speed);
1419 root 1.3
1420 root 1.9 /* Max is determined by armour */
1421     if (op->speed > max)
1422     op->speed = max;
1423 elmex 1.1
1424 root 1.9 if (op->type == PLAYER)
1425     {
1426     /* f is a number the represents the number of kg above (positive num)
1427     * or below (negative number) that the player is carrying. If above
1428     * weight limit, then player suffers a speed reduction based on how
1429     * much above he is, and what is max carry is
1430     */
1431     f = (op->carrying / 1000) - max_carry[op->stats.Str];
1432     if (f > 0)
1433     op->speed = op->speed / (1.0 + f / max_carry[op->stats.Str]);
1434 elmex 1.1 }
1435    
1436 root 1.9 op->speed += bonus_speed / 10.0; /* Not affected by limits */
1437    
1438     /* Put a lower limit on speed. Note with this speed, you move once every
1439     * 100 ticks or so. This amounts to once every 12 seconds of realtime.
1440     */
1441     op->speed = op->speed * speed_reduce_from_disease;
1442 elmex 1.1
1443 root 1.9 if (op->speed < 0.01 && op->type == PLAYER)
1444     op->speed = 0.01;
1445    
1446     if (op->type == PLAYER)
1447     {
1448     float M, W, s, D, K, S, M2;
1449 elmex 1.1
1450 root 1.9 /* (This formula was made by vidarl@ifi.uio.no)
1451     * Note that we never used these values again - basically
1452     * all of these could be subbed into one big equation, but
1453     * that would just be a real pain to read.
1454     */
1455     M = (max_carry[op->stats.Str] - 121) / 121.0;
1456     M2 = max_carry[op->stats.Str] / 100.0;
1457     W = weapon_weight / 20000.0;
1458     s = 2 - weapon_speed / 10.0;
1459     D = (op->stats.Dex - 14) / 14.0;
1460     K = 1 + M / 3.0 - W / (3 * M2) + op->speed / 5.0 + D / 2.0;
1461     K *= (4 + op->level) / (float) (6 + op->level) * 1.2;
1462     if (K <= 0)
1463     K = 0.01;
1464     S = op->speed / (K * s);
1465     op->contr->weapon_sp = S;
1466     }
1467     /* I want to limit the power of small monsters with big weapons: */
1468     if (op->type != PLAYER && op->arch != NULL && op->stats.dam > op->arch->clone.stats.dam * 3)
1469     op->stats.dam = op->arch->clone.stats.dam * 3;
1470    
1471     /* Prevent overflows of wc - best you can get is ABS(120) - this
1472     * should be more than enough - remember, AC is also in 8 bits,
1473     * so its value is the same.
1474     */
1475     if (wc > 120)
1476     wc = 120;
1477     else if (wc < -120)
1478     wc = -120;
1479     op->stats.wc = wc;
1480    
1481     if (ac > 120)
1482     ac = 120;
1483     else if (ac < -120)
1484     ac = -120;
1485     op->stats.ac = ac;
1486    
1487     /* if for some reason the creature doesn't have any move type,
1488     * give them walking as a default.
1489     * The second case is a special case - to more closely mimic the
1490     * old behaviour - if your flying, your not walking - just
1491     * one or the other.
1492     */
1493     if (op->move_type == 0)
1494     op->move_type = MOVE_WALK;
1495     else if (op->move_type & (MOVE_FLY_LOW | MOVE_FLY_HIGH))
1496     op->move_type &= ~MOVE_WALK;
1497 elmex 1.1
1498 root 1.9 update_ob_speed (op);
1499 elmex 1.1
1500 root 1.9 /* It is quite possible that a player's spell costing might have changed,
1501     * so we will check that now.
1502     */
1503     if (op->type == PLAYER)
1504     esrv_update_spells (op->contr);
1505 elmex 1.1 }
1506    
1507     /*
1508     * Returns true if the given player is a legal class.
1509     * The function to add and remove class-bonuses to the stats doesn't
1510     * check if the stat becomes negative, thus this function
1511     * merely checks that all stats are 1 or more, and returns
1512     * false otherwise.
1513     */
1514    
1515 root 1.9 int
1516     allowed_class (const object *op)
1517     {
1518     return op->stats.Dex > 0 && op->stats.Str > 0 && op->stats.Con > 0 &&
1519     op->stats.Int > 0 && op->stats.Wis > 0 && op->stats.Pow > 0 && op->stats.Cha > 0;
1520 elmex 1.1 }
1521    
1522     /*
1523     * set the new dragon name after gaining levels or
1524     * changing ability focus (later this can be extended to
1525     * eventually change the player's face and animation)
1526     *
1527     * Note that the title is written to 'own_title' in the
1528     * player struct. This should be changed to 'ext_title'
1529     * as soon as clients support this!
1530     * Please, anyone, write support for 'ext_title'.
1531     */
1532 root 1.9 void
1533     set_dragon_name (object *pl, const object *abil, const object *skin)
1534     {
1535     int atnr = -1; /* attacknumber of highest level */
1536     int level = 0; /* highest level */
1537 elmex 1.1 int i;
1538    
1539     /* Perhaps do something more clever? */
1540 root 1.9 if (!abil || !skin)
1541     return;
1542    
1543 elmex 1.1 /* first, look for the highest level */
1544 root 1.9 for (i = 0; i < NROFATTACKS; i++)
1545     {
1546     if (atnr_is_dragon_enabled (i) && (atnr == -1 || abil->resist[i] > abil->resist[atnr]))
1547     {
1548     level = abil->resist[i];
1549     atnr = i;
1550     }
1551 elmex 1.1 }
1552 root 1.9
1553 elmex 1.1 /* now if there are equals at highest level, pick the one with focus,
1554     or else at random */
1555 root 1.9 if (atnr_is_dragon_enabled (abil->stats.exp) && abil->resist[abil->stats.exp] >= level)
1556 elmex 1.1 atnr = abil->stats.exp;
1557 root 1.9
1558     level = (int) (level / 5.);
1559    
1560 elmex 1.1 /* now set the new title */
1561 root 1.9 if (pl->contr != NULL)
1562     {
1563     if (level == 0)
1564     sprintf (pl->contr->title, "%s hatchling", attacks[atnr]);
1565     else if (level == 1)
1566     sprintf (pl->contr->title, "%s wyrm", attacks[atnr]);
1567     else if (level == 2)
1568     sprintf (pl->contr->title, "%s wyvern", attacks[atnr]);
1569     else if (level == 3)
1570     sprintf (pl->contr->title, "%s dragon", attacks[atnr]);
1571 elmex 1.1 else
1572 root 1.9 {
1573     /* special titles for extra high resistance! */
1574     if (skin->resist[atnr] > 80)
1575     sprintf (pl->contr->title, "legendary %s dragon", attacks[atnr]);
1576     else if (skin->resist[atnr] > 50)
1577     sprintf (pl->contr->title, "ancient %s dragon", attacks[atnr]);
1578     else
1579     sprintf (pl->contr->title, "big %s dragon", attacks[atnr]);
1580     }
1581 elmex 1.1 }
1582 root 1.9
1583     strcpy (pl->contr->own_title, "");
1584 elmex 1.1 }
1585    
1586     /*
1587     * This function is called when a dragon-player gains
1588     * an overall level. Here, the dragon might gain new abilities
1589     * or change the ability-focus.
1590     */
1591 root 1.9 void
1592     dragon_level_gain (object *who)
1593     {
1594     object *abil = NULL; /* pointer to dragon ability force */
1595     object *skin = NULL; /* pointer to dragon skin force */
1596     object *tmp = NULL; /* tmp. object */
1597     char buf[MAX_BUF]; /* tmp. string buffer */
1598    
1599     /* now grab the 'dragon_ability'-forces from the player's inventory */
1600     for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
1601     {
1602     if (tmp->type == FORCE)
1603     {
1604     if (strcmp (tmp->arch->name, "dragon_ability_force") == 0)
1605     abil = tmp;
1606     if (strcmp (tmp->arch->name, "dragon_skin_force") == 0)
1607     skin = tmp;
1608     }
1609     }
1610     /* if the force is missing -> bail out */
1611     if (abil == NULL)
1612     return;
1613    
1614     /* The ability_force keeps track of maximum level ever achieved.
1615     * New abilties can only be gained by surpassing this max level
1616     */
1617     if (who->level > abil->level)
1618     {
1619     /* increase our focused ability */
1620     abil->resist[abil->stats.exp]++;
1621    
1622    
1623     if (abil->resist[abil->stats.exp] > 0 && abil->resist[abil->stats.exp] % 5 == 0)
1624     {
1625     /* time to hand out a new ability-gift */
1626     dragon_ability_gain (who, (int) abil->stats.exp, (int) ((1 + abil->resist[abil->stats.exp]) / 5.));
1627     }
1628    
1629     if (abil->last_eat > 0 && atnr_is_dragon_enabled (abil->last_eat))
1630     {
1631     /* apply new ability focus */
1632     sprintf (buf, "Your metabolism now focuses on %s!", change_resist_msg[abil->last_eat]);
1633     new_draw_info (NDI_UNIQUE | NDI_BLUE, 0, who, buf);
1634    
1635     abil->stats.exp = abil->last_eat;
1636     abil->last_eat = 0;
1637     }
1638    
1639     abil->level = who->level;
1640     }
1641    
1642     /* last but not least, set the new title for the dragon */
1643     set_dragon_name (who, abil, skin);
1644 elmex 1.1 }
1645    
1646     /* Handy function - given the skill name skill_name, we find the skill
1647     * archetype/object, set appropriate values, and insert it into
1648     * the object (op) that is passed.
1649     * We return the skill - this makes it easier for calling functions that
1650     * want to do something with it immediately.
1651     */
1652 root 1.9 object *
1653     give_skill_by_name (object *op, const char *skill_name)
1654 elmex 1.1 {
1655 root 1.9 object *skill_obj;
1656 elmex 1.1
1657 root 1.9 skill_obj = get_archetype_by_skill_name (skill_name, SKILL);
1658     if (!skill_obj)
1659     {
1660     LOG (llevError, "add_player_exp: couldn't find skill %s\n", skill_name);
1661     return NULL;
1662     }
1663     /* clear the flag - exp goes into this bucket, but player
1664     * still doesn't know it.
1665     */
1666     CLEAR_FLAG (skill_obj, FLAG_CAN_USE_SKILL);
1667     skill_obj->stats.exp = 0;
1668     skill_obj->level = 1;
1669     insert_ob_in_ob (skill_obj, op);
1670     if (op->contr)
1671     {
1672     op->contr->last_skill_ob[skill_obj->subtype] = skill_obj;
1673     op->contr->last_skill_exp[skill_obj->subtype] = -1;
1674 elmex 1.1 }
1675 root 1.9 return skill_obj;
1676 elmex 1.1 }
1677    
1678    
1679     /* player_lvl_adj() - for the new exp system. we are concerned with
1680     * whether the player gets more hp, sp and new levels.
1681     * Note this this function should only be called for players. Monstes
1682     * don't really gain levels
1683     * who is the player, op is what we are checking to gain the level
1684     * (eg, skill)
1685     */
1686 root 1.9 void
1687     player_lvl_adj (object *who, object *op)
1688     {
1689     char buf[MAX_BUF];
1690    
1691     if (!op) /* when rolling stats */
1692     op = who;
1693    
1694     if (op->level < settings.max_level && op->stats.exp >= level_exp (op->level + 1, who->expmul))
1695     {
1696     op->level++;
1697    
1698     if (op != NULL && op == who && op->stats.exp > 1 && is_dragon_pl (who))
1699     dragon_level_gain (who);
1700    
1701     /* Only roll these if it is the player (who) that gained the level */
1702     if (op == who && (who->level < 11) && who->type == PLAYER)
1703     {
1704     who->contr->levhp[who->level] = die_roll (2, 4, who, PREFER_HIGH) + 1;
1705     who->contr->levsp[who->level] = die_roll (2, 3, who, PREFER_HIGH);
1706     who->contr->levgrace[who->level] = die_roll (2, 2, who, PREFER_HIGH) - 1;
1707     }
1708    
1709     fix_player (who);
1710     if (op->level > 1)
1711     {
1712     if (op->type != PLAYER)
1713     sprintf (buf, "You are now level %d in the %s skill.", op->level, &op->name);
1714     else
1715     sprintf (buf, "You are now level %d.", op->level);
1716     if (who)
1717     new_draw_info (NDI_UNIQUE | NDI_RED, 0, who, buf);
1718     }
1719     player_lvl_adj (who, op); /* To increase more levels */
1720     }
1721     else if (op->level > 1 && op->stats.exp < level_exp (op->level, who->expmul))
1722     {
1723     op->level--;
1724     fix_player (who);
1725     if (op->type != PLAYER)
1726     {
1727     sprintf (buf, "You are now level %d in the %s skill.", op->level, &op->name);
1728     new_draw_info (NDI_UNIQUE | NDI_RED, 0, who, buf);
1729 root 1.3 }
1730 root 1.9 player_lvl_adj (who, op); /* To decrease more levels */
1731 elmex 1.1 }
1732 root 1.9 /* check if the spell data has changed */
1733     esrv_update_spells (who->contr);
1734 elmex 1.1 }
1735    
1736     /*
1737     * Returns how much experience is needed for a player to become
1738     * the given level. level should really never exceed max_level
1739     */
1740    
1741 root 1.9 sint64
1742     level_exp (int level, double expmul)
1743     {
1744     if (level > settings.max_level)
1745     return (sint64) (expmul * levels[settings.max_level]);
1746     return (sint64) (expmul * levels[level]);
1747 elmex 1.1 }
1748    
1749     /*
1750     * Ensure that the permanent experience requirements in an exp object are met.
1751     * This really just checks 'op to make sure the perm_exp value is within
1752     * proper range. Note that the checking of what is passed through
1753     * has been reduced. Since there is now a proper field for perm_exp,
1754     * this can now work on a much larger set of objects.
1755     */
1756 root 1.9 void
1757     calc_perm_exp (object *op)
1758 elmex 1.1 {
1759 root 1.9 int p_exp_min;
1760    
1761     /* Ensure that our permanent experience minimum is met.
1762     * permenent_exp_ratio is an integer percentage, we divide by 100
1763     * to get the fraction */
1764     p_exp_min = (int) (settings.permanent_exp_ratio * (float) (op->stats.exp) / 100);
1765    
1766     if (op->perm_exp < p_exp_min)
1767     op->perm_exp = p_exp_min;
1768    
1769     /* Cap permanent experience. */
1770     if (op->perm_exp < 0)
1771     op->perm_exp = 0;
1772     else if (op->perm_exp > (sint64) MAX_EXPERIENCE)
1773     op->perm_exp = MAX_EXPERIENCE;
1774 elmex 1.1 }
1775    
1776    
1777     /* Add experience to a player - exp should only be positive.
1778     * Updates permanent exp for the skill we are adding to.
1779     * skill_name is the skill to add exp to. Skill name can be
1780     * NULL, in which case exp increases the players general
1781     * total, but not any particular skill.
1782     * flag is what to do if the player doesn't have the skill:
1783     */
1784    
1785 root 1.9 static void
1786     add_player_exp (object *op, sint64 exp, const char *skill_name, int flag)
1787 elmex 1.1 {
1788 elmex 1.4 object *skill_obj = NULL;
1789     sint64 limit, exp_to_add;
1790     int i;
1791    
1792     /* prevents some forms of abuse. */
1793     if (op->contr->braced)
1794     exp = exp / 5;
1795    
1796     /* Try to find the matching skill.
1797     * We do a shortcut/time saving mechanism first - see if it matches
1798     * chosen_skill. This means we don't need to search through
1799     * the players inventory.
1800     */
1801     if (skill_name)
1802     {
1803 root 1.9 if (op->chosen_skill && op->chosen_skill->type == SKILL && !strcmp (skill_name, op->chosen_skill->skill))
1804 elmex 1.4 skill_obj = op->chosen_skill;
1805     else
1806     {
1807     for (i = 0; i < NUM_SKILLS; i++)
1808 root 1.9 if (op->contr->last_skill_ob[i] && !strcmp (op->contr->last_skill_ob[i]->skill, skill_name))
1809 elmex 1.4 {
1810     skill_obj = op->contr->last_skill_ob[i];
1811     break;
1812     }
1813 root 1.3
1814 elmex 1.4 /* Player doesn't have the skill. Check to see what to do, and give
1815     * it to the player if necessary
1816     */
1817     if (!skill_obj)
1818     {
1819     if (flag == SK_EXP_NONE)
1820     return;
1821     else if (flag == SK_EXP_ADD_SKILL)
1822     give_skill_by_name (op, skill_name);
1823 root 1.3 }
1824     }
1825 elmex 1.1 }
1826    
1827 elmex 1.4 if (flag != SK_EXP_SKILL_ONLY)
1828     {
1829     /* Basically, you can never gain more experience in one shot
1830     * than half what you need to gain for next level.
1831     */
1832     exp_to_add = exp;
1833     limit = (levels[op->level + 1] - levels[op->level]) / 2;
1834     if (exp_to_add > limit)
1835     exp_to_add = limit;
1836    
1837 root 1.9 ADD_EXP (op->stats.exp, (sint64) ((float) exp_to_add * (skill_obj ? skill_obj->expmul : 1)));
1838 elmex 1.4 if (settings.permanent_exp_ratio)
1839     {
1840 root 1.9 ADD_EXP (op->perm_exp, (sint64) ((float) exp_to_add * PERM_EXP_GAIN_RATIO * (skill_obj ? skill_obj->expmul : 1)));
1841 elmex 1.4 calc_perm_exp (op);
1842     }
1843    
1844     player_lvl_adj (op, NULL);
1845     }
1846    
1847     if (skill_obj)
1848     {
1849     exp_to_add = exp;
1850     limit = (levels[skill_obj->level + 1] - levels[skill_obj->level]) / 2;
1851     if (exp_to_add > limit)
1852     exp_to_add = limit;
1853    
1854     ADD_EXP (skill_obj->stats.exp, exp_to_add);
1855     if (settings.permanent_exp_ratio)
1856     {
1857 root 1.9 skill_obj->perm_exp += (sint64) ((float) exp_to_add * PERM_EXP_GAIN_RATIO);
1858 elmex 1.4 calc_perm_exp (skill_obj);
1859     }
1860 elmex 1.1
1861 elmex 1.4 player_lvl_adj (op, skill_obj);
1862 elmex 1.1 }
1863     }
1864    
1865     /* This function checks to make sure that object 'op' can
1866     * lost 'exp' experience. It returns the amount of exp
1867     * object 'op' can in fact lose - it basically makes
1868     * adjustments based on permanent exp and the like.
1869     * This function should always be used for losing experience -
1870     * the 'exp' value passed should be positive - this is the
1871     * amount that should get subtract from the player.
1872     */
1873 root 1.9 sint64
1874     check_exp_loss (const object *op, sint64 exp)
1875 elmex 1.1 {
1876 root 1.9 sint64 del_exp;
1877 elmex 1.1
1878 root 1.9 if (exp > op->stats.exp)
1879     exp = op->stats.exp;
1880     if (settings.permanent_exp_ratio)
1881     {
1882     del_exp = (sint64) ((op->stats.exp - op->perm_exp) * PERM_EXP_MAX_LOSS_RATIO);
1883     if (del_exp < 0)
1884     del_exp = 0;
1885     if (exp > del_exp)
1886     exp = del_exp;
1887 elmex 1.1 }
1888 root 1.9 return exp;
1889 elmex 1.1 }
1890    
1891 root 1.9 sint64
1892     check_exp_adjust (const object *op, sint64 exp)
1893 elmex 1.1 {
1894 root 1.9 if (exp < 0)
1895     return check_exp_loss (op, exp);
1896     else
1897     return MIN (exp, (sint64) MAX_EXPERIENCE - op->stats.exp);
1898 elmex 1.1 }
1899    
1900    
1901     /* Subtracts experience from player.
1902     * if skill is set and flag == SK_SUBTRACT_SKILL_EXP, then we
1903     * only subtract from the matching skill. Otherwise,
1904     * this subtracts a portion from all
1905     * skills the player has. Eg, if we figure the player is losing 10%
1906     * of his total exp, what happens is he loses 10% from all his skills.
1907     * Note that if permanent exp is used, player may not in fact lose
1908     * as much as listed. Eg, if player has gotten reduced to the point
1909     * where everything is at the minimum perm exp, he would lose nothing.
1910     * exp is the amount of exp to subtract - thus, it should be
1911     * a postive number.
1912     */
1913 root 1.9 static void
1914     subtract_player_exp (object *op, sint64 exp, const char *skill, int flag)
1915 elmex 1.1 {
1916 root 1.9 float fraction = (float) exp / (float) op->stats.exp;
1917     object *tmp;
1918     sint64 del_exp;
1919    
1920     for (tmp = op->inv; tmp; tmp = tmp->below)
1921     if (tmp->type == SKILL && tmp->stats.exp)
1922     {
1923     if (flag == SK_SUBTRACT_SKILL_EXP && skill && !strcmp (tmp->skill, skill))
1924     {
1925     del_exp = check_exp_loss (tmp, exp);
1926     tmp->stats.exp -= del_exp;
1927     player_lvl_adj (op, tmp);
1928     }
1929     else if (flag != SK_SUBTRACT_SKILL_EXP)
1930     {
1931     /* only want to process other skills if we are not trying
1932     * to match a specific skill.
1933     */
1934     del_exp = check_exp_loss (tmp, (sint64) (tmp->stats.exp * fraction));
1935     tmp->stats.exp -= del_exp;
1936     player_lvl_adj (op, tmp);
1937     }
1938     }
1939     if (flag != SK_SUBTRACT_SKILL_EXP)
1940     {
1941     del_exp = check_exp_loss (op, exp);
1942     op->stats.exp -= del_exp;
1943     player_lvl_adj (op, NULL);
1944 elmex 1.1 }
1945     }
1946    
1947    
1948    
1949     /* change_exp() - changes experience to a player/monster. This
1950     * does bounds checking to make sure we don't overflow the max exp.
1951     *
1952     * The exp passed is typically not modified much by this function -
1953     * it is assumed the caller has modified the exp as needed.
1954     * skill_name is the skill that should get the exp added.
1955     * flag is what to do if player doesn't have the skill.
1956     * these last two values are only used for players.
1957     */
1958 root 1.9
1959     void
1960     change_exp (object *op, sint64 exp, const char *skill_name, int flag)
1961     {
1962 elmex 1.1
1963     #ifdef EXP_DEBUG
1964 root 1.9 # ifndef WIN32
1965     LOG (llevDebug, "change_exp() called for %s, exp = %lld\n", query_name (op), exp);
1966     # else
1967     LOG (llevDebug, "change_exp() called for %s, exp = %I64d\n", query_name (op), exp);
1968     # endif
1969 elmex 1.1 #endif
1970    
1971 root 1.9 /* safety */
1972     if (!op)
1973     {
1974     LOG (llevError, "change_exp() called for null object!\n");
1975     return;
1976     }
1977    
1978     /* if no change in exp, just return - most of the below code
1979     * won't do anything if the value is 0 anyways.
1980     */
1981     if (exp == 0)
1982     return;
1983    
1984     /* Monsters are easy - we just adjust their exp - we
1985     * don't adjust level, since in most cases it is unrelated to
1986     * the exp they have - the monsters exp represents what its
1987     * worth.
1988     */
1989     if (op->type != PLAYER)
1990     {
1991     /* Sanity check */
1992     if (!QUERY_FLAG (op, FLAG_ALIVE))
1993     return;
1994    
1995     /* reset exp to max allowed value. We subtract from
1996     * MAX_EXPERIENCE to prevent overflows. If the player somehow has
1997     * more than max exp, just return.
1998     */
1999     if (exp > 0 && (op->stats.exp > (sint64) (MAX_EXPERIENCE - exp)))
2000     {
2001     exp = MAX_EXPERIENCE - op->stats.exp;
2002     if (exp < 0)
2003     return;
2004 root 1.3 }
2005 elmex 1.1
2006 root 1.9 op->stats.exp += exp;
2007 elmex 1.1 }
2008 root 1.9 else
2009     { /* Players only */
2010     if (exp > 0)
2011     add_player_exp (op, exp, skill_name, flag);
2012     else
2013     /* note that when you lose exp, it doesn't go against
2014     * a particular skill, so we don't need to pass that
2015     * along.
2016     */
2017     subtract_player_exp (op, FABS (exp), skill_name, flag);
2018 elmex 1.1
2019     }
2020     }
2021    
2022     /* Applies a death penalty experience, the size of this is defined by the
2023     * settings death_penalty_percentage and death_penalty_levels, and by the
2024     * amount of permenent experience, whichever gives the lowest loss.
2025     */
2026    
2027 root 1.9 void
2028     apply_death_exp_penalty (object *op)
2029     {
2030     object *tmp;
2031     sint64 loss;
2032     sint64 percentage_loss; /* defined by the setting 'death_penalty_percent' */
2033     sint64 level_loss; /* defined by the setting 'death_penalty_levels */
2034    
2035     for (tmp = op->inv; tmp; tmp = tmp->below)
2036     if (tmp->type == SKILL && tmp->stats.exp)
2037     {
2038    
2039     percentage_loss = tmp->stats.exp * settings.death_penalty_ratio / 100;
2040     level_loss = tmp->stats.exp - levels[MAX (0, tmp->level - settings.death_penalty_level)];
2041    
2042     /* With the revised exp system, you can get cases where
2043     * losing several levels would still require that you have more
2044     * exp than you currently have - this is true if the levels
2045     * tables is a lot harder.
2046     */
2047     if (level_loss < 0)
2048     level_loss = 0;
2049 root 1.3
2050 root 1.9 loss = check_exp_loss (tmp, MIN (level_loss, percentage_loss));
2051 root 1.3
2052 root 1.9 tmp->stats.exp -= loss;
2053     player_lvl_adj (op, tmp);
2054     }
2055 elmex 1.1
2056 root 1.9 percentage_loss = op->stats.exp * settings.death_penalty_ratio / 100;
2057     level_loss = op->stats.exp - levels[MAX (0, op->level - settings.death_penalty_level)];
2058     if (level_loss < 0)
2059     level_loss = 0;
2060     loss = check_exp_loss (op, MIN (level_loss, percentage_loss));
2061 elmex 1.1
2062 root 1.9 op->stats.exp -= loss;
2063     player_lvl_adj (op, NULL);
2064 elmex 1.1 }
2065    
2066     /* This function takes an object (monster/player, op), and
2067     * determines if it makes a basic save throw by looking at the
2068     * save_throw table. level is the effective level to make
2069     * the save at, and bonus is any plus/bonus (typically based on
2070     * resistance to particular attacktype.
2071     * Returns 1 if op makes his save, 0 if he failed
2072     */
2073 root 1.9 int
2074     did_make_save (const object *op, int level, int bonus)
2075 elmex 1.1 {
2076 root 1.9 if (level > MAX_SAVE_LEVEL)
2077     level = MAX_SAVE_LEVEL;
2078 elmex 1.1
2079 root 1.9 if ((random_roll (1, 20, op, PREFER_HIGH) + bonus) < savethrow[level])
2080     return 0;
2081     return 1;
2082 elmex 1.1 }