ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.29
Committed: Tue Aug 7 21:58:25 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.28: +28 -27 lines
Log Message:
- lots of clamping on stats
- optimisations/bugfixes in update_stats
- disease progression now uses lots of ad-hoc clamping on various values

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