ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.34
Committed: Sun Aug 12 07:04:48 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.33: +0 -1 lines
Log Message:
*** empty log message ***

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     /* check to see if an object is infectable:
288     * objects with immunity aren't infectable.
289     * objects already infected aren't infectable.
290     * dead objects aren't infectable.
291     * undead objects are infectible only if specifically named.
292     */
293 root 1.4 int
294     infect_object (object *victim, object *disease, int force)
295     {
296     object *tmp;
297     object *new_disease;
298 elmex 1.1
299 root 1.4 /* don't infect inanimate objects */
300     if (!QUERY_FLAG (victim, FLAG_MONSTER) && !(victim->type == PLAYER))
301     return 0;
302    
303     /* check and see if victim can catch disease: diseases
304     * are specific
305     */
306     if (!is_susceptible_to_disease (victim, disease))
307     return 0;
308    
309     /* roll the dice on infection before doing the inventory check! */
310     if (!force && (random_roll (0, 126, victim, PREFER_HIGH) >= disease->stats.wc))
311     return 0;
312 elmex 1.1
313 root 1.4 /* do an immunity check */
314     if (victim->head)
315     tmp = victim->head->inv;
316     else
317     tmp = victim->inv;
318    
319     /* There used to (IMO) be a flaw in the below - it used to be the case
320     * that if level check was done for both immunity and disease. This could
321     * result in a person with multiple afflictions of the same disease
322     * (eg, level 1 cold, level 2 cold, level 3 cold, etc), as long as
323     * they were cast in that same order. Instead, change it so that
324     * if you diseased, you can't get diseased more.
325     */
326    
327 pippijn 1.15 for ( /* tmp initialised in if, above */ ; tmp; tmp = tmp->below)
328 root 1.4 {
329 root 1.19 if (tmp->type == SIGN && tmp->name == disease->name && tmp->level >= disease->level)
330 pippijn 1.15 return 0; /* Immune! */
331 root 1.19 else if (tmp->type == DISEASE && tmp->name == disease->name)
332 root 1.4 return 0; /* already diseased */
333     }
334    
335     /* If we've gotten this far, go ahead and infect the victim. */
336 root 1.10 new_disease = disease->clone ();
337 root 1.4 new_disease->stats.food = disease->stats.maxgrace;
338     new_disease->value = disease->stats.maxhp;
339     new_disease->stats.wc -= disease->last_grace; /* self-limiting factor */
340    
341     /* Unfortunately, set_owner does the wrong thing to the skills pointers
342     * resulting in exp going into the owners *current* chosen skill.
343     */
344    
345 root 1.11 if (disease->owner)
346 root 1.4 {
347 root 1.11 new_disease->set_owner (disease->owner);
348 root 1.4
349     /* Only need to update skill if different */
350     if (new_disease->skill != disease->skill)
351     new_disease->skill = disease->skill;
352     }
353     else
354     { /* for diseases which are passed by hitting, set owner and praying skill */
355     if (disease->env && disease->env->type == PLAYER)
356     {
357     object *player = disease->env;
358    
359 root 1.11 new_disease->set_owner (player);
360 root 1.4
361     /* the skill pointer for these diseases should already be set up -
362     * hardcoding in 'praying' is not the right approach.
363     */
364 root 1.2 }
365 elmex 1.1 }
366    
367 root 1.24 insert_ob_in_ob (new_disease, victim->head_ ());
368 root 1.4 /* This appears to be a horrible case of overloading 'NO_PASS'
369     * for meaning in the diseases.
370     */
371     new_disease->move_block = 0;
372     if (new_disease->owner && new_disease->owner->type == PLAYER)
373     {
374     char buf[128];
375    
376     /* if the disease has a title, it has a special infection message
377     * This messages is printed in the form MESSAGE victim
378     */
379     if (new_disease->title)
380     sprintf (buf, "%s %s!!", &disease->title, &victim->name);
381     else
382     sprintf (buf, "You infect %s with your disease, %s!", &victim->name, &new_disease->name);
383    
384     if (victim->type == PLAYER)
385     new_draw_info (NDI_UNIQUE | NDI_RED, 0, new_disease->owner, buf);
386     else
387     new_draw_info (0, 4, new_disease->owner, buf);
388 elmex 1.1 }
389 root 1.30
390 root 1.4 if (victim->type == PLAYER)
391     new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, "You suddenly feel ill.");
392 elmex 1.1
393 root 1.4 return 1;
394 elmex 1.1
395     }
396    
397     /* this function monitors the symptoms caused by the disease (if any),
398     causes symptoms, and modifies existing symptoms in the case of
399     existing diseases. */
400 root 1.4 int
401     do_symptoms (object *disease)
402     {
403     object *symptom;
404     object *victim;
405     object *tmp;
406    
407     victim = disease->env;
408    
409 root 1.30 if (!victim)
410     return 0; /* no-one to inflict symptoms on */
411    
412 root 1.4 /* This is a quick hack - for whatever reason, disease->env will point
413     * back to disease, causing endless loops. Why this happens really needs
414     * to be found, but this should at least prevent the infinite loops.
415     */
416 root 1.30 //TODO: should no longer be the case, monitor, and remove
417     if (victim == disease)
418     {
419     LOG (llevError | logBacktrace, "%s: disease->env points to itself", disease->debug_desc ());
420     return 0;
421     }
422 root 1.4
423     symptom = find_symptom (disease);
424 root 1.30 if (!symptom)
425 root 1.4 {
426     /* no symptom? need to generate one! */
427     object *new_symptom;
428    
429     /* first check and see if the carrier of the disease is immune. If so, no symptoms! */
430     if (!is_susceptible_to_disease (victim, disease))
431     return 0;
432    
433     /* check for an actual immunity */
434     /* do an immunity check */
435     if (victim->head)
436     tmp = victim->head->inv;
437     else
438     tmp = victim->inv;
439    
440 pippijn 1.15 for ( /* tmp initialised in if, above */ ; tmp; tmp = tmp->below)
441 root 1.30 if (tmp->type == SIGN) /* possibly an immunity, or diseased */
442     if (tmp->name == disease->name && tmp->level >= disease->level)
443     return 0; /*Immune! */
444 root 1.2
445 root 1.26 new_symptom = get_archetype ("symptom");
446 root 1.4
447     /* Something special done with dam. We want diseases to be more
448     * random in what they'll kill, so we'll make the damage they
449     * do random, note, this has a weird effect with progressive diseases.
450     */
451     if (disease->stats.dam != 0)
452     {
453     int dam = disease->stats.dam;
454    
455     /* reduce the damage, on average, 50%, and making things random. */
456    
457 root 1.18 dam = random_roll (1, abs (dam), victim, PREFER_LOW);
458 root 1.4 if (disease->stats.dam < 0)
459     dam = -dam;
460 root 1.30
461 root 1.4 new_symptom->stats.dam = dam;
462 root 1.2 }
463 elmex 1.1
464 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
465 root 1.29 new_symptom->stats.food = new_symptom->stats.maxgrace;
466 root 1.4
467     new_symptom->name = new_symptom->name_pl = disease->name;
468    
469     new_symptom->level = disease->level;
470     new_symptom->speed = disease->speed;
471     new_symptom->value = 0;
472 root 1.22
473     for (int i = 0; i < NUM_STATS; ++i)
474     new_symptom->stats.stat (i) = disease->stats.stat (i);
475    
476 root 1.29 new_symptom->stats.sp = disease->stats.sp;
477     new_symptom->stats.food = disease->last_eat;
478 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
479 root 1.29 new_symptom->last_sp = disease->last_sp;
480     new_symptom->stats.exp = 0;
481     new_symptom->stats.hp = disease->stats.hp;
482     new_symptom->msg = disease->msg;
483     new_symptom->attacktype = disease->attacktype;
484     new_symptom->other_arch = disease->other_arch;
485 root 1.4
486 root 1.11 new_symptom->set_owner (disease->owner);
487 root 1.4
488     if (new_symptom->skill != disease->skill)
489     new_symptom->skill = disease->skill;
490    
491     new_symptom->move_block = 0;
492     insert_ob_in_ob (new_symptom, victim);
493     return 1;
494     }
495    
496 root 1.23 /* now deal with progressing diseases: we increase the debility
497 root 1.4 * caused by the symptoms.
498     */
499 root 1.29 if (disease->stats.ac)
500 root 1.4 {
501 root 1.29 symptom->value = clamp (symptom->value + disease->stats.ac, 0, 100*100);
502 root 1.4
503 root 1.23 float scale = 1.f + symptom->value / 100.f;
504 root 1.22
505 root 1.4 /* now rescale all the debilities */
506 root 1.22 for (int i = 0; i < NUM_STATS; ++i)
507 root 1.31 symptom->stats.stat (i) = clamp (int (scale * disease->stats.stat (i)), -128, 127);
508 root 1.22
509 root 1.29 symptom->stats.dam = clamp (scale * disease->stats.dam , -1024, 1024);
510     symptom->stats.food = clamp (scale * disease->last_eat , -1024, 1024);
511     symptom->stats.maxsp = clamp (scale * disease->stats.maxsp, -1024, 1024);
512     symptom->stats.sp = clamp (scale * disease->stats.sp , -1024, 1024);
513     symptom->stats.hp = clamp (scale * disease->stats.hp , -1024, 1024);
514 root 1.22 symptom->stats.exp = 0;
515 root 1.33 symptom->last_sp = disease->last_sp ? clamp (disease->last_sp / scale, 1, 1024) : 0;
516 root 1.29 symptom->msg = disease->msg;
517     symptom->attacktype = disease->attacktype;
518     symptom->other_arch = disease->other_arch;
519 elmex 1.1 }
520 root 1.23
521 root 1.4 SET_FLAG (symptom, FLAG_APPLIED);
522 root 1.13 victim->update_stats ();
523 root 1.23
524 root 1.4 return 1;
525 elmex 1.1 }
526    
527     /* grants immunity to plagues we've seen before. */
528 root 1.4 int
529     grant_immunity (object *disease)
530     {
531     object *immunity;
532 elmex 1.1 object *walk;
533 root 1.4
534 elmex 1.1 /* Don't give immunity to this disease if last_heal is set. */
535 root 1.4 if (disease->last_heal)
536     return 0;
537 elmex 1.1 /* first, search for an immunity of the same name */
538 root 1.4 for (walk = disease->env->inv; walk; walk = walk->below)
539     {
540 root 1.19 if (walk->type == 98 && disease->name == walk->name)
541 root 1.4 {
542     walk->level = disease->level;
543     return 1; /* just update the existing immunity. */
544     }
545     }
546     immunity = get_archetype ("immunity");
547 root 1.3 immunity->name = disease->name;
548 elmex 1.1 immunity->level = disease->level;
549     immunity->move_block = 0;
550 root 1.4 insert_ob_in_ob (immunity, disease->env);
551 elmex 1.1 return 1;
552    
553     }
554    
555    
556     /* make the symptom do the nasty things it does */
557    
558 root 1.4 int
559     move_symptom (object *symptom)
560     {
561     object *victim = symptom->env;
562     object *new_ob;
563     int sp_reduce;
564    
565     if (victim == NULL || victim->map == NULL)
566     { /* outside a monster/player, die immediately */
567 root 1.9 symptom->destroy ();
568 root 1.4 return 0;
569     }
570    
571     if (symptom->stats.dam > 0)
572     hit_player (victim, symptom->stats.dam, symptom, symptom->attacktype, 1);
573     else
574     hit_player (victim, (int) MAX (1, -victim->stats.maxhp * symptom->stats.dam / 100.0), symptom, symptom->attacktype, 1);
575    
576     if (symptom->stats.maxsp > 0)
577     sp_reduce = symptom->stats.maxsp;
578     else
579     sp_reduce = (int) MAX (1, victim->stats.maxsp * symptom->stats.maxsp / 100.0);
580     victim->stats.sp = MAX (0, victim->stats.sp - sp_reduce);
581    
582     /* create the symptom "other arch" object and drop it here
583     * under every part of the monster
584     * The victim may well have died.
585     */
586 elmex 1.1
587 root 1.4 if (victim->map == NULL)
588     return 0;
589     if (symptom->other_arch)
590     {
591     object *tmp;
592    
593     tmp = victim;
594     if (tmp->head != NULL)
595     tmp = tmp->head;
596 pippijn 1.15 for ( /*tmp initialised above */ ; tmp != NULL; tmp = tmp->more)
597 root 1.4 {
598     new_ob = arch_to_object (symptom->other_arch);
599     new_ob->x = tmp->x;
600     new_ob->y = tmp->y;
601     new_ob->map = victim->map;
602     insert_ob_in_map (new_ob, victim->map, victim, 0);
603 root 1.2 }
604 elmex 1.1 }
605 root 1.4 new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, symptom->msg);
606    
607     return 1;
608 elmex 1.1 }
609    
610 root 1.20 /* possibly infect due to direct physical contact
611     * i.e., AT_PHYSICAL-- called from "hit_player_attacktype" */
612 root 1.4 int
613     check_physically_infect (object *victim, object *hitter)
614     {
615 root 1.20 /* search for diseases, give every disease a chance to infect */
616     for (object *disease = hitter->inv; disease; disease = disease->below)
617     if (disease->type == DISEASE)
618     infect_object (victim, disease, 0);
619 root 1.4
620 elmex 1.1 return 1;
621     }
622    
623 root 1.20 // find a disease in someone
624 root 1.4 object *
625     find_disease (object *victim)
626     {
627 root 1.20 for (object *disease = victim->inv; disease; disease = disease->below)
628     if (disease->type == DISEASE)
629     return disease;
630 root 1.4
631 root 1.20 return 0;
632 elmex 1.1 }
633 root 1.4
634 elmex 1.1 /* do the cure disease stuff, from the spell "cure disease" */
635 root 1.4 int
636     cure_disease (object *sufferer, object *caster)
637     {
638     object *disease, *next;
639     int casting_level;
640     int cure = 0;
641    
642     if (caster)
643     casting_level = caster->level;
644     else
645     casting_level = 1000; /* if null caster, CURE all. */
646    
647     for (disease = sufferer->inv; disease; disease = next)
648     {
649     next = disease->below;
650    
651     if (disease->type == DISEASE)
652     { /* attempt to cure this disease */
653 root 1.21 /* If caster level is higher than disease level, cure chance
654 root 1.4 * is automatic. If lower, then the chance is basically
655     * 1 in level_diff - if there is a 5 level difference, chance
656     * is 1 in 5.
657     */
658     if ((casting_level >= disease->level) || (!(random_roll (0, (disease->level - casting_level - 1), caster, PREFER_LOW))))
659     {
660     remove_symptoms (disease);
661     cure = 1;
662 root 1.9
663 root 1.4 if (caster)
664 root 1.21 change_exp (caster, disease->stats.exp, caster->chosen_skill ? caster->chosen_skill->skill : (const char *) 0, 0);
665 root 1.9
666     disease->destroy ();
667 root 1.2 }
668     }
669 elmex 1.1 }
670 root 1.21
671 root 1.4 if (cure)
672     {
673     /* Only draw these messages once */
674     if (caster)
675     new_draw_info_format (NDI_UNIQUE, 0, caster, "You cure a disease!");
676 root 1.21
677 root 1.4 new_draw_info (NDI_UNIQUE, 0, sufferer, "You no longer feel diseased.");
678 elmex 1.1 }
679 root 1.21
680 elmex 1.1 return 1;
681     }
682    
683     /* reduces disease progression: reduce_symptoms
684     * return true if we actually reduce a disease.
685     */
686 root 1.4 int
687     reduce_symptoms (object *sufferer, int reduction)
688     {
689     object *walk;
690     int success = 0;
691    
692     for (walk = sufferer->inv; walk; walk = walk->below)
693     {
694     if (walk->type == SYMPTOM)
695     {
696     if (walk->value > 0)
697     {
698     success = 1;
699 root 1.29 walk->value = max (0, walk->value - 2 * reduction);
700 root 1.4 /* give the disease time to modify this symptom,
701     * and reduce its severity. */
702     walk->speed_left = 0;
703 root 1.2 }
704 root 1.4 }
705 elmex 1.1 }
706 root 1.29
707 root 1.4 if (success)
708     new_draw_info (NDI_UNIQUE, 0, sufferer, "Your illness seems less severe.");
709 root 1.29
710 root 1.4 return success;
711 elmex 1.1 }