ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/living.c
Revision: 1.1.1.3 (vendor branch)
Committed: Wed Mar 15 14:04:36 2006 UTC (18 years, 2 months ago) by elmex
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15
Changes since 1.1.1.2: +23 -20 lines
Log Message:
cvs -z9 -d:ext:elmex@cvs.schmorp.de:/schmorpforge import cf.schmorp.de UPSTREAM UPSTREAM_2006_03_15

File Contents

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