ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.30
Committed: Tue Aug 7 22:13:52 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.29: +17 -13 lines
Log Message:
increase range of some player-stats, we have the memory and we need the precision

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.25 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 pippijn 1.17 *
4 root 1.25 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.17 *
8 root 1.27 * Crossfire TRT is free software: you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation, either version 3 of the License, or
11     * (at your option) any later version.
12 pippijn 1.17 *
13 root 1.27 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 root 1.25 *
18 root 1.27 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 pippijn 1.17 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22     */
23 elmex 1.1
24 root 1.21 /* This file contains all the code implementing diseases,
25     * except for odds and ends in attack.c and in
26     * living.c
27     */
28 elmex 1.1
29     /*
30    
31     For DISEASES:
32     Stat Property Definition
33    
34     attacktype Attack effects Attacktype of the disease. usu. AT_GODPOWER.
35     other_arch Creation object created and dropped when symptom moved.
36     title Message When the "disease" "infects" something, it will
37     print "title victim!!!" to the player who owns
38 root 1.2 the "disease".
39 elmex 1.1 wc+ Infectiousness How well the plague spreads person-to-person
40     magic+ Range range of infection
41     Stats* Disability What stats are reduced by the disease (str con...)
42     maxhp+ Persistence How long the disease can last OUTSIDE the host.
43     value TimeLeft Counter for persistence
44     dam^ Damage How much damage it does (%?).
45     maxgrace+ Duration How long before the disease is naturally cured.
46     food DurCount Counter for Duration
47    
48     speed Speed How often the disease moves.
49     last_sp^ Lethargy Percentage of max speed--10 = 10% speed.
50    
51     maxsp^ Mana deplete Saps mana.
52     ac^ Progressiveness How the diseases increases in severity.
53     last_eat*^ Deplete food saps food if negative
54     last_heal GrantImmunity If nonzero, disease does NOT grant immunity
55     when it runs out
56    
57     exp experience experience awarded when plague cured
58     hp*^ ReduceRegen reduces regeneration of disease-bearer
59     sp*^ ReduceSpRegen reduces spellpoint regeneration
60    
61     name Name Name of the plague
62     msg message What the plague says when it strikes.
63     race those affected species/race the plague strikes (* = everything)
64     level Plague Level General description of the plague's deadliness
65     armour Attenuation reduction in wc per generation of disease.
66     This builds in a self-limiting factor.
67    
68    
69     Explanations:
70     * means this # should be negative to cause adverse effect.
71     + means that this effect is modulated in spells by ldur
72     ^ means that this effect is modulated in spells by ldam
73    
74     attacktype is the attacktype used by the disease to smite "dam" damage with.
75    
76     wc/127 is the chance of someone in range catching it.
77    
78     magic is the range at which infection may occur. If negative, the range is
79     NOT level dependent.
80    
81     Stats are stat modifications. These should typically be negative.
82    
83     maxhp is how long the disease will persist if the host dies and "drops" it,
84     in "disease moves", i.e., moves of the disease. If negative, permanent.
85    
86    
87     value is the counter for maxhp, it starts at maxhp and drops...
88    
89     dam if positive, it is straight damage. if negative, a %-age.
90    
91     maxgrace how long in "disease moves" the disease lasts in the host, if negative,
92     permanent until cured.
93    
94     food if negative, disease is permanent. otherwise, decreases at <speed>,
95     disease goes away at food=0, set to "maxgrace" on infection.
96    
97     speed is the speed of the disease, how fast "disease moves" occur.
98    
99     last_sp is the lethargy imposed on the player by the disease. A lethargy
100     of "1" reduces the players speed to 1% of its normal value.
101    
102     maxsp how much mana is sapped per "disease move". if negative, a %-age is
103     taken.
104    
105     ac every "disease move" the severity of the symptoms are increased by
106     ac/100. (severity = 1 + (accumlated_progression)/100)
107    
108     last_eat increases food usage if negative.
109    
110    
111    
112     For SYMPTOMS:
113    
114     Stats modify stats
115     hp modify regen
116     value progression counter (multiplier = value/100)
117     food modify food use (from last_eat in DISEASE)
118     maxsp suck mana ( as noted for DISEASE)
119     last_sp Lethargy
120     msg What to say
121     speed speed of movement, from DISEASE
122    
123    
124     */
125    
126    
127     #include <global.h>
128     #include <object.h>
129     #include <living.h>
130 root 1.14 #include <sproto.h>
131 elmex 1.1 #include <spells.h>
132     #include <sounds.h>
133     #include <skills.h>
134    
135     /* IMPLEMENTATION NOTES
136 root 1.2
137     Diseases may be contageous. They are objects which exist in a player's
138 elmex 1.1 inventory. They themselves do nothing, except modify Symptoms, or
139     spread to other live objects. Symptoms are what actually damage the player:
140     these are their own object. */
141    
142     /* check if victim is susceptible to disease. */
143 root 1.4 static int
144     is_susceptible_to_disease (object *victim, object *disease)
145 elmex 1.1 {
146 root 1.4 if (!QUERY_FLAG (victim, FLAG_ALIVE))
147     return 0;
148 elmex 1.1
149 root 1.4 if (strstr (disease->race, "*") && !QUERY_FLAG (victim, FLAG_UNDEAD))
150     return 1;
151 elmex 1.1
152 root 1.28 if ((disease->race == shstr_undead) && QUERY_FLAG (victim, FLAG_UNDEAD))
153 root 1.4 return 1;
154 elmex 1.1
155 root 1.4 if ((victim->race && strstr (disease->race, victim->race)) || strstr (disease->race, victim->name))
156     return 1;
157    
158     return 0;
159 elmex 1.1 }
160    
161 root 1.4 int
162     move_disease (object *disease)
163     {
164     /* first task is to determine if the disease is inside or outside of someone.
165     * If outside, we decrement 'value' until we're gone.
166     */
167    
168 root 1.29 if (!disease->env)
169 root 1.4 { /* we're outside of someone */
170     if (disease->stats.maxhp > 0)
171     disease->value--;
172 root 1.9
173 root 1.29 if (!disease->value)
174 root 1.4 {
175 root 1.9 disease->destroy ();
176 root 1.4 return 1;
177 root 1.2 }
178 root 1.4 }
179     else
180     {
181     /* if we're inside a person, have the disease run its course */
182 root 1.29 /* negative/zero food denotes "perpetual" diseases. */
183 root 1.4 if (disease->stats.food > 0)
184     {
185     disease->stats.food--;
186 root 1.9
187 root 1.29 if (!disease->stats.food)
188 root 1.4 {
189     remove_symptoms (disease); /* remove the symptoms of this disease */
190     grant_immunity (disease);
191 root 1.9 disease->destroy ();
192 root 1.4 return 1;
193 root 1.2 }
194     }
195 elmex 1.1 }
196 root 1.9
197 root 1.4 /* check to see if we infect others */
198     check_infection (disease);
199 elmex 1.1
200 root 1.4 /* impose or modify the symptoms of the disease */
201     if (disease->env && is_susceptible_to_disease (disease->env, disease))
202     do_symptoms (disease);
203 elmex 1.1
204 root 1.4 return 0;
205 elmex 1.1 }
206    
207     /* remove any symptoms of disease
208     * Modified by MSW 2003-03-28 do try to find all the symptom the
209     * player may have - I think through some odd interactoins with
210     * disease level and player level and whatnot, a player could get
211     * more than one symtpom to a disease.
212     */
213 root 1.4
214     int
215     remove_symptoms (object *disease)
216     {
217     object *symptom, *victim = NULL;
218    
219     while ((symptom = find_symptom (disease)) != NULL)
220     {
221     if (!victim)
222     victim = symptom->env;
223 root 1.9
224     symptom->destroy ();
225 root 1.4 }
226 root 1.9
227 root 1.4 if (victim)
228 root 1.13 victim->update_stats ();
229 root 1.30
230 root 1.4 return 0;
231 elmex 1.1 }
232    
233     /* argument is a disease */
234 root 1.4 object *
235     find_symptom (object *disease)
236     {
237 elmex 1.1 object *walk;
238    
239     /* check the inventory for symptoms */
240 root 1.4 for (walk = disease->env->inv; walk; walk = walk->below)
241 root 1.19 if (walk->name == disease->name && walk->type == SYMPTOM)
242 root 1.4 return walk;
243 root 1.30
244 elmex 1.1 return NULL;
245     }
246 root 1.4
247 elmex 1.1 /* searches around for more victims to infect */
248 root 1.4 int
249     check_infection (object *disease)
250     {
251     int x, y, range, mflags;
252 root 1.6 maptile *map, *map2;
253 root 1.4 object *tmp;
254    
255     range = abs (disease->magic);
256 root 1.7
257 root 1.4 if (disease->env)
258     {
259 root 1.7 x = disease->env->x;
260     y = disease->env->y;
261 root 1.4 map = disease->env->map;
262     }
263     else
264     {
265 root 1.7 x = disease->x;
266     y = disease->y;
267 root 1.4 map = disease->map;
268     }
269    
270 root 1.7 if (!map)
271 root 1.4 return 0;
272 root 1.7
273     for (int i = x - range; i <= x + range; i++)
274     for (int j = y - range; j <= y + range; j++)
275     {
276     sint16 i2, j2;
277     mflags = get_map_flags (map, &map2, i, j, &i2, &j2);
278    
279     if (!(mflags & P_OUT_OF_MAP) && (mflags & P_IS_ALIVE))
280 root 1.12 for (tmp = GET_MAP_OB (map2, i2, j2); tmp; tmp = tmp->above)
281 root 1.7 infect_object (tmp, disease, 0);
282     }
283    
284 root 1.4 return 1;
285 elmex 1.1 }
286    
287    
288     /* check to see if an object is infectable:
289     * objects with immunity aren't infectable.
290     * objects already infected aren't infectable.
291     * dead objects aren't infectable.
292     * undead objects are infectible only if specifically named.
293     */
294 root 1.4 int
295     infect_object (object *victim, object *disease, int force)
296     {
297     object *tmp;
298     object *new_disease;
299 elmex 1.1
300 root 1.4 /* don't infect inanimate objects */
301     if (!QUERY_FLAG (victim, FLAG_MONSTER) && !(victim->type == PLAYER))
302     return 0;
303    
304     /* check and see if victim can catch disease: diseases
305     * are specific
306     */
307     if (!is_susceptible_to_disease (victim, disease))
308     return 0;
309    
310     /* roll the dice on infection before doing the inventory check! */
311     if (!force && (random_roll (0, 126, victim, PREFER_HIGH) >= disease->stats.wc))
312     return 0;
313 elmex 1.1
314 root 1.4 /* do an immunity check */
315     if (victim->head)
316     tmp = victim->head->inv;
317     else
318     tmp = victim->inv;
319    
320     /* There used to (IMO) be a flaw in the below - it used to be the case
321     * that if level check was done for both immunity and disease. This could
322     * result in a person with multiple afflictions of the same disease
323     * (eg, level 1 cold, level 2 cold, level 3 cold, etc), as long as
324     * they were cast in that same order. Instead, change it so that
325     * if you diseased, you can't get diseased more.
326     */
327    
328 pippijn 1.15 for ( /* tmp initialised in if, above */ ; tmp; tmp = tmp->below)
329 root 1.4 {
330 root 1.19 if (tmp->type == SIGN && tmp->name == disease->name && tmp->level >= disease->level)
331 pippijn 1.15 return 0; /* Immune! */
332 root 1.19 else if (tmp->type == DISEASE && tmp->name == disease->name)
333 root 1.4 return 0; /* already diseased */
334     }
335    
336     /* If we've gotten this far, go ahead and infect the victim. */
337 root 1.10 new_disease = disease->clone ();
338 root 1.4 new_disease->stats.food = disease->stats.maxgrace;
339     new_disease->value = disease->stats.maxhp;
340     new_disease->stats.wc -= disease->last_grace; /* self-limiting factor */
341    
342     /* Unfortunately, set_owner does the wrong thing to the skills pointers
343     * resulting in exp going into the owners *current* chosen skill.
344     */
345    
346 root 1.11 if (disease->owner)
347 root 1.4 {
348 root 1.11 new_disease->set_owner (disease->owner);
349 root 1.4
350     /* Only need to update skill if different */
351     if (new_disease->skill != disease->skill)
352     new_disease->skill = disease->skill;
353     }
354     else
355     { /* for diseases which are passed by hitting, set owner and praying skill */
356     if (disease->env && disease->env->type == PLAYER)
357     {
358     object *player = disease->env;
359    
360 root 1.11 new_disease->set_owner (player);
361 root 1.4
362     /* the skill pointer for these diseases should already be set up -
363     * hardcoding in 'praying' is not the right approach.
364     */
365 root 1.2 }
366 elmex 1.1 }
367    
368 root 1.24 insert_ob_in_ob (new_disease, victim->head_ ());
369 root 1.4 /* This appears to be a horrible case of overloading 'NO_PASS'
370     * for meaning in the diseases.
371     */
372     new_disease->move_block = 0;
373     if (new_disease->owner && new_disease->owner->type == PLAYER)
374     {
375     char buf[128];
376    
377     /* if the disease has a title, it has a special infection message
378     * This messages is printed in the form MESSAGE victim
379     */
380     if (new_disease->title)
381     sprintf (buf, "%s %s!!", &disease->title, &victim->name);
382     else
383     sprintf (buf, "You infect %s with your disease, %s!", &victim->name, &new_disease->name);
384    
385     if (victim->type == PLAYER)
386     new_draw_info (NDI_UNIQUE | NDI_RED, 0, new_disease->owner, buf);
387     else
388     new_draw_info (0, 4, new_disease->owner, buf);
389 elmex 1.1 }
390 root 1.30
391 root 1.4 if (victim->type == PLAYER)
392     new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, "You suddenly feel ill.");
393 elmex 1.1
394 root 1.4 return 1;
395 elmex 1.1
396     }
397    
398     /* this function monitors the symptoms caused by the disease (if any),
399     causes symptoms, and modifies existing symptoms in the case of
400     existing diseases. */
401 root 1.4 int
402     do_symptoms (object *disease)
403     {
404     object *symptom;
405     object *victim;
406     object *tmp;
407    
408     victim = disease->env;
409    
410 root 1.30 if (!victim)
411     return 0; /* no-one to inflict symptoms on */
412    
413 root 1.4 /* This is a quick hack - for whatever reason, disease->env will point
414     * back to disease, causing endless loops. Why this happens really needs
415     * to be found, but this should at least prevent the infinite loops.
416     */
417 root 1.30 //TODO: should no longer be the case, monitor, and remove
418     if (victim == disease)
419     {
420     LOG (llevError | logBacktrace, "%s: disease->env points to itself", disease->debug_desc ());
421     return 0;
422     }
423 root 1.4
424     symptom = find_symptom (disease);
425 root 1.30 if (!symptom)
426 root 1.4 {
427     /* no symptom? need to generate one! */
428     object *new_symptom;
429    
430     /* first check and see if the carrier of the disease is immune. If so, no symptoms! */
431     if (!is_susceptible_to_disease (victim, disease))
432     return 0;
433    
434     /* check for an actual immunity */
435     /* do an immunity check */
436     if (victim->head)
437     tmp = victim->head->inv;
438     else
439     tmp = victim->inv;
440    
441 pippijn 1.15 for ( /* tmp initialised in if, above */ ; tmp; tmp = tmp->below)
442 root 1.30 if (tmp->type == SIGN) /* possibly an immunity, or diseased */
443     if (tmp->name == disease->name && tmp->level >= disease->level)
444     return 0; /*Immune! */
445 root 1.2
446 root 1.26 new_symptom = get_archetype ("symptom");
447 root 1.4
448     /* Something special done with dam. We want diseases to be more
449     * random in what they'll kill, so we'll make the damage they
450     * do random, note, this has a weird effect with progressive diseases.
451     */
452     if (disease->stats.dam != 0)
453     {
454     int dam = disease->stats.dam;
455    
456     /* reduce the damage, on average, 50%, and making things random. */
457    
458 root 1.18 dam = random_roll (1, abs (dam), victim, PREFER_LOW);
459 root 1.4 if (disease->stats.dam < 0)
460     dam = -dam;
461 root 1.30
462 root 1.4 new_symptom->stats.dam = dam;
463 root 1.2 }
464 elmex 1.1
465 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
466 root 1.29 new_symptom->stats.food = new_symptom->stats.maxgrace;
467 root 1.4
468     new_symptom->name = new_symptom->name_pl = disease->name;
469    
470     new_symptom->level = disease->level;
471     new_symptom->speed = disease->speed;
472     new_symptom->value = 0;
473 root 1.22
474     for (int i = 0; i < NUM_STATS; ++i)
475     new_symptom->stats.stat (i) = disease->stats.stat (i);
476    
477 root 1.29 new_symptom->stats.sp = disease->stats.sp;
478     new_symptom->stats.food = disease->last_eat;
479 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
480 root 1.29 new_symptom->last_sp = disease->last_sp;
481     new_symptom->stats.exp = 0;
482     new_symptom->stats.hp = disease->stats.hp;
483     new_symptom->msg = disease->msg;
484     new_symptom->attacktype = disease->attacktype;
485     new_symptom->other_arch = disease->other_arch;
486 root 1.4
487 root 1.11 new_symptom->set_owner (disease->owner);
488 root 1.4
489     if (new_symptom->skill != disease->skill)
490     new_symptom->skill = disease->skill;
491    
492     new_symptom->move_block = 0;
493     insert_ob_in_ob (new_symptom, victim);
494     return 1;
495     }
496    
497 root 1.23 /* now deal with progressing diseases: we increase the debility
498 root 1.4 * caused by the symptoms.
499     */
500 root 1.29 if (disease->stats.ac)
501 root 1.4 {
502 root 1.29 symptom->value = clamp (symptom->value + disease->stats.ac, 0, 100*100);
503 root 1.4
504 root 1.23 float scale = 1.f + symptom->value / 100.f;
505 root 1.22
506 root 1.4 /* now rescale all the debilities */
507 root 1.22 for (int i = 0; i < NUM_STATS; ++i)
508 root 1.29 symptom->stats.stat (i) = clamp (scale * disease->stats.stat (i), -MAX_STAT, MAX_STAT);
509 root 1.22
510 root 1.29 symptom->stats.dam = clamp (scale * disease->stats.dam , -1024, 1024);
511     symptom->stats.food = clamp (scale * disease->last_eat , -1024, 1024);
512     symptom->stats.maxsp = clamp (scale * disease->stats.maxsp, -1024, 1024);
513     symptom->last_sp = clamp (scale * disease->last_sp , -1024, 1024);
514     symptom->stats.sp = clamp (scale * disease->stats.sp , -1024, 1024);
515     symptom->stats.hp = clamp (scale * disease->stats.hp , -1024, 1024);
516 root 1.22 symptom->stats.exp = 0;
517    
518 root 1.29 symptom->msg = disease->msg;
519     symptom->attacktype = disease->attacktype;
520     symptom->other_arch = disease->other_arch;
521 elmex 1.1 }
522 root 1.23
523 root 1.4 SET_FLAG (symptom, FLAG_APPLIED);
524 root 1.13 victim->update_stats ();
525 root 1.23
526 root 1.4 return 1;
527 elmex 1.1 }
528    
529     /* grants immunity to plagues we've seen before. */
530 root 1.4 int
531     grant_immunity (object *disease)
532     {
533     object *immunity;
534 elmex 1.1 object *walk;
535 root 1.4
536 elmex 1.1 /* Don't give immunity to this disease if last_heal is set. */
537 root 1.4 if (disease->last_heal)
538     return 0;
539 elmex 1.1 /* first, search for an immunity of the same name */
540 root 1.4 for (walk = disease->env->inv; walk; walk = walk->below)
541     {
542 root 1.19 if (walk->type == 98 && disease->name == walk->name)
543 root 1.4 {
544     walk->level = disease->level;
545     return 1; /* just update the existing immunity. */
546     }
547     }
548     immunity = get_archetype ("immunity");
549 root 1.3 immunity->name = disease->name;
550 elmex 1.1 immunity->level = disease->level;
551     immunity->move_block = 0;
552 root 1.4 insert_ob_in_ob (immunity, disease->env);
553 elmex 1.1 return 1;
554    
555     }
556    
557    
558     /* make the symptom do the nasty things it does */
559    
560 root 1.4 int
561     move_symptom (object *symptom)
562     {
563     object *victim = symptom->env;
564     object *new_ob;
565     int sp_reduce;
566    
567     if (victim == NULL || victim->map == NULL)
568     { /* outside a monster/player, die immediately */
569 root 1.9 symptom->destroy ();
570 root 1.4 return 0;
571     }
572    
573     if (symptom->stats.dam > 0)
574     hit_player (victim, symptom->stats.dam, symptom, symptom->attacktype, 1);
575     else
576     hit_player (victim, (int) MAX (1, -victim->stats.maxhp * symptom->stats.dam / 100.0), symptom, symptom->attacktype, 1);
577    
578     if (symptom->stats.maxsp > 0)
579     sp_reduce = symptom->stats.maxsp;
580     else
581     sp_reduce = (int) MAX (1, victim->stats.maxsp * symptom->stats.maxsp / 100.0);
582     victim->stats.sp = MAX (0, victim->stats.sp - sp_reduce);
583    
584     /* create the symptom "other arch" object and drop it here
585     * under every part of the monster
586     * The victim may well have died.
587     */
588 elmex 1.1
589 root 1.4 if (victim->map == NULL)
590     return 0;
591     if (symptom->other_arch)
592     {
593     object *tmp;
594    
595     tmp = victim;
596     if (tmp->head != NULL)
597     tmp = tmp->head;
598 pippijn 1.15 for ( /*tmp initialised above */ ; tmp != NULL; tmp = tmp->more)
599 root 1.4 {
600     new_ob = arch_to_object (symptom->other_arch);
601     new_ob->x = tmp->x;
602     new_ob->y = tmp->y;
603     new_ob->map = victim->map;
604     insert_ob_in_map (new_ob, victim->map, victim, 0);
605 root 1.2 }
606 elmex 1.1 }
607 root 1.4 new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, symptom->msg);
608    
609     return 1;
610 elmex 1.1 }
611    
612 root 1.20 /* possibly infect due to direct physical contact
613     * i.e., AT_PHYSICAL-- called from "hit_player_attacktype" */
614 root 1.4 int
615     check_physically_infect (object *victim, object *hitter)
616     {
617 root 1.20 /* search for diseases, give every disease a chance to infect */
618     for (object *disease = hitter->inv; disease; disease = disease->below)
619     if (disease->type == DISEASE)
620     infect_object (victim, disease, 0);
621 root 1.4
622 elmex 1.1 return 1;
623     }
624    
625 root 1.20 // find a disease in someone
626 root 1.4 object *
627     find_disease (object *victim)
628     {
629 root 1.20 for (object *disease = victim->inv; disease; disease = disease->below)
630     if (disease->type == DISEASE)
631     return disease;
632 root 1.4
633 root 1.20 return 0;
634 elmex 1.1 }
635 root 1.4
636 elmex 1.1 /* do the cure disease stuff, from the spell "cure disease" */
637 root 1.4 int
638     cure_disease (object *sufferer, object *caster)
639     {
640     object *disease, *next;
641     int casting_level;
642     int cure = 0;
643    
644     if (caster)
645     casting_level = caster->level;
646     else
647     casting_level = 1000; /* if null caster, CURE all. */
648    
649     for (disease = sufferer->inv; disease; disease = next)
650     {
651     next = disease->below;
652    
653     if (disease->type == DISEASE)
654     { /* attempt to cure this disease */
655 root 1.21 /* If caster level is higher than disease level, cure chance
656 root 1.4 * is automatic. If lower, then the chance is basically
657     * 1 in level_diff - if there is a 5 level difference, chance
658     * is 1 in 5.
659     */
660     if ((casting_level >= disease->level) || (!(random_roll (0, (disease->level - casting_level - 1), caster, PREFER_LOW))))
661     {
662     remove_symptoms (disease);
663     cure = 1;
664 root 1.9
665 root 1.4 if (caster)
666 root 1.21 change_exp (caster, disease->stats.exp, caster->chosen_skill ? caster->chosen_skill->skill : (const char *) 0, 0);
667 root 1.9
668     disease->destroy ();
669 root 1.2 }
670     }
671 elmex 1.1 }
672 root 1.21
673 root 1.4 if (cure)
674     {
675     /* Only draw these messages once */
676     if (caster)
677     new_draw_info_format (NDI_UNIQUE, 0, caster, "You cure a disease!");
678 root 1.21
679 root 1.4 new_draw_info (NDI_UNIQUE, 0, sufferer, "You no longer feel diseased.");
680 elmex 1.1 }
681 root 1.21
682 elmex 1.1 return 1;
683     }
684    
685     /* reduces disease progression: reduce_symptoms
686     * return true if we actually reduce a disease.
687     */
688 root 1.4 int
689     reduce_symptoms (object *sufferer, int reduction)
690     {
691     object *walk;
692     int success = 0;
693    
694     for (walk = sufferer->inv; walk; walk = walk->below)
695     {
696     if (walk->type == SYMPTOM)
697     {
698     if (walk->value > 0)
699     {
700     success = 1;
701 root 1.29 walk->value = max (0, walk->value - 2 * reduction);
702 root 1.4 /* give the disease time to modify this symptom,
703     * and reduce its severity. */
704     walk->speed_left = 0;
705 root 1.2 }
706 root 1.4 }
707 elmex 1.1 }
708 root 1.29
709 root 1.4 if (success)
710     new_draw_info (NDI_UNIQUE, 0, sufferer, "Your illness seems less severe.");
711 root 1.29
712 root 1.4 return success;
713 elmex 1.1 }