ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.19
Committed: Mon Feb 5 02:07:40 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_0
Changes since 1.18: +5 -5 lines
Log Message:
remove many strcmps on shstr, added fast strcmp wrapper that only etsts for inequality

File Contents

# User Rev Content
1 elmex 1.1 /*
2 pippijn 1.17 * CrossFire, A Multiplayer game for X-windows
3     *
4     * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5     * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
6     * Copyright (C) 1992 Frank Tore Johansen
7     *
8     * This program 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 2 of the License, or
11     * (at your option) any later version.
12     *
13     * 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     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *
22     * The authors can be reached via e-mail to <crossfire@schmorp.de>
23     */
24 elmex 1.1
25     /* This file contains all the code implementing diseases,
26     except for odds and ends in attack.c and in
27 root 1.2 living.c*/
28 elmex 1.1
29    
30    
31     /*
32    
33     For DISEASES:
34     Stat Property Definition
35    
36     attacktype Attack effects Attacktype of the disease. usu. AT_GODPOWER.
37     other_arch Creation object created and dropped when symptom moved.
38     title Message When the "disease" "infects" something, it will
39     print "title victim!!!" to the player who owns
40 root 1.2 the "disease".
41 elmex 1.1 wc+ Infectiousness How well the plague spreads person-to-person
42     magic+ Range range of infection
43     Stats* Disability What stats are reduced by the disease (str con...)
44     maxhp+ Persistence How long the disease can last OUTSIDE the host.
45     value TimeLeft Counter for persistence
46     dam^ Damage How much damage it does (%?).
47     maxgrace+ Duration How long before the disease is naturally cured.
48     food DurCount Counter for Duration
49    
50     speed Speed How often the disease moves.
51     last_sp^ Lethargy Percentage of max speed--10 = 10% speed.
52    
53     maxsp^ Mana deplete Saps mana.
54     ac^ Progressiveness How the diseases increases in severity.
55     last_eat*^ Deplete food saps food if negative
56     last_heal GrantImmunity If nonzero, disease does NOT grant immunity
57     when it runs out
58    
59     exp experience experience awarded when plague cured
60     hp*^ ReduceRegen reduces regeneration of disease-bearer
61     sp*^ ReduceSpRegen reduces spellpoint regeneration
62    
63     name Name Name of the plague
64     msg message What the plague says when it strikes.
65     race those affected species/race the plague strikes (* = everything)
66     level Plague Level General description of the plague's deadliness
67     armour Attenuation reduction in wc per generation of disease.
68     This builds in a self-limiting factor.
69    
70    
71     Explanations:
72     * means this # should be negative to cause adverse effect.
73     + means that this effect is modulated in spells by ldur
74     ^ means that this effect is modulated in spells by ldam
75    
76     attacktype is the attacktype used by the disease to smite "dam" damage with.
77    
78     wc/127 is the chance of someone in range catching it.
79    
80     magic is the range at which infection may occur. If negative, the range is
81     NOT level dependent.
82    
83     Stats are stat modifications. These should typically be negative.
84    
85     maxhp is how long the disease will persist if the host dies and "drops" it,
86     in "disease moves", i.e., moves of the disease. If negative, permanent.
87    
88    
89     value is the counter for maxhp, it starts at maxhp and drops...
90    
91     dam if positive, it is straight damage. if negative, a %-age.
92    
93     maxgrace how long in "disease moves" the disease lasts in the host, if negative,
94     permanent until cured.
95    
96     food if negative, disease is permanent. otherwise, decreases at <speed>,
97     disease goes away at food=0, set to "maxgrace" on infection.
98    
99     speed is the speed of the disease, how fast "disease moves" occur.
100    
101     last_sp is the lethargy imposed on the player by the disease. A lethargy
102     of "1" reduces the players speed to 1% of its normal value.
103    
104     maxsp how much mana is sapped per "disease move". if negative, a %-age is
105     taken.
106    
107     ac every "disease move" the severity of the symptoms are increased by
108     ac/100. (severity = 1 + (accumlated_progression)/100)
109    
110     last_eat increases food usage if negative.
111    
112    
113    
114     For SYMPTOMS:
115    
116     Stats modify stats
117     hp modify regen
118     value progression counter (multiplier = value/100)
119     food modify food use (from last_eat in DISEASE)
120     maxsp suck mana ( as noted for DISEASE)
121     last_sp Lethargy
122     msg What to say
123     speed speed of movement, from DISEASE
124    
125    
126     */
127    
128    
129     #include <global.h>
130     #include <object.h>
131     #include <living.h>
132 root 1.14 #include <sproto.h>
133 elmex 1.1 #include <spells.h>
134     #include <sounds.h>
135     #include <skills.h>
136    
137     /* IMPLEMENTATION NOTES
138 root 1.2
139     Diseases may be contageous. They are objects which exist in a player's
140 elmex 1.1 inventory. They themselves do nothing, except modify Symptoms, or
141     spread to other live objects. Symptoms are what actually damage the player:
142     these are their own object. */
143    
144     /* check if victim is susceptible to disease. */
145 root 1.4 static int
146     is_susceptible_to_disease (object *victim, object *disease)
147 elmex 1.1 {
148 root 1.4 if (!QUERY_FLAG (victim, FLAG_ALIVE))
149     return 0;
150 elmex 1.1
151 root 1.4 if (strstr (disease->race, "*") && !QUERY_FLAG (victim, FLAG_UNDEAD))
152     return 1;
153 elmex 1.1
154 root 1.4 if ((disease->race == undead_name) && QUERY_FLAG (victim, FLAG_UNDEAD))
155     return 1;
156 elmex 1.1
157 root 1.4 if ((victim->race && strstr (disease->race, victim->race)) || strstr (disease->race, victim->name))
158     return 1;
159    
160     return 0;
161 elmex 1.1 }
162    
163 root 1.4 int
164     move_disease (object *disease)
165     {
166     /* first task is to determine if the disease is inside or outside of someone.
167     * If outside, we decrement 'value' until we're gone.
168     */
169    
170     if (disease->env == NULL)
171     { /* we're outside of someone */
172     if (disease->stats.maxhp > 0)
173     disease->value--;
174 root 1.9
175 root 1.4 if (disease->value == 0)
176     {
177 root 1.9 disease->destroy ();
178 root 1.4 return 1;
179 root 1.2 }
180 root 1.4 }
181     else
182     {
183     /* if we're inside a person, have the disease run its course */
184     /* negative foods denote "perpetual" diseases. */
185     if (disease->stats.food > 0)
186     {
187     disease->stats.food--;
188 root 1.9
189 root 1.4 if (disease->stats.food == 0)
190     {
191     remove_symptoms (disease); /* remove the symptoms of this disease */
192     grant_immunity (disease);
193 root 1.9 disease->destroy ();
194 root 1.4 return 1;
195 root 1.2 }
196     }
197 elmex 1.1 }
198 root 1.9
199 root 1.4 /* check to see if we infect others */
200     check_infection (disease);
201 elmex 1.1
202 root 1.4 /* impose or modify the symptoms of the disease */
203     if (disease->env && is_susceptible_to_disease (disease->env, disease))
204     do_symptoms (disease);
205 elmex 1.1
206 root 1.4 return 0;
207 elmex 1.1 }
208    
209     /* remove any symptoms of disease
210     * Modified by MSW 2003-03-28 do try to find all the symptom the
211     * player may have - I think through some odd interactoins with
212     * disease level and player level and whatnot, a player could get
213     * more than one symtpom to a disease.
214     */
215 root 1.4
216     int
217     remove_symptoms (object *disease)
218     {
219     object *symptom, *victim = NULL;
220    
221     while ((symptom = find_symptom (disease)) != NULL)
222     {
223     if (!victim)
224     victim = symptom->env;
225 root 1.9
226     symptom->destroy ();
227 root 1.4 }
228 root 1.9
229 root 1.4 if (victim)
230 root 1.13 victim->update_stats ();
231 root 1.4 return 0;
232 elmex 1.1 }
233    
234     /* argument is a disease */
235 root 1.4 object *
236     find_symptom (object *disease)
237     {
238 elmex 1.1 object *walk;
239    
240     /* check the inventory for symptoms */
241 root 1.4 for (walk = disease->env->inv; walk; walk = walk->below)
242 root 1.19 if (walk->name == disease->name && walk->type == SYMPTOM)
243 root 1.4 return walk;
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.4 insert_ob_in_ob (new_disease, victim);
369     /* 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.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    
398    
399     /* this function monitors the symptoms caused by the disease (if any),
400     causes symptoms, and modifies existing symptoms in the case of
401     existing diseases. */
402    
403 root 1.4 int
404     do_symptoms (object *disease)
405     {
406     object *symptom;
407     object *victim;
408     object *tmp;
409    
410     victim = disease->env;
411    
412     /* 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    
417     if (victim == NULL || victim == disease)
418     return 0; /* no-one to inflict symptoms on */
419    
420     symptom = find_symptom (disease);
421     if (symptom == NULL)
422     {
423     /* no symptom? need to generate one! */
424     object *new_symptom;
425    
426     /* first check and see if the carrier of the disease is immune. If so, no symptoms! */
427     if (!is_susceptible_to_disease (victim, disease))
428     return 0;
429    
430     /* check for an actual immunity */
431     /* do an immunity check */
432     if (victim->head)
433     tmp = victim->head->inv;
434     else
435     tmp = victim->inv;
436    
437 pippijn 1.15 for ( /* tmp initialised in if, above */ ; tmp; tmp = tmp->below)
438 root 1.4 {
439     if (tmp->type == SIGN) /* possibly an immunity, or diseased */
440 root 1.19 if (tmp->name == disease->name && tmp->level >= disease->level)
441 root 1.4 return 0; /*Immune! */
442 root 1.2 }
443    
444 root 1.4 new_symptom = get_archetype (ARCH_SYMPTOM);
445    
446     /* Something special done with dam. We want diseases to be more
447     * random in what they'll kill, so we'll make the damage they
448     * do random, note, this has a weird effect with progressive diseases.
449     */
450     if (disease->stats.dam != 0)
451     {
452     int dam = disease->stats.dam;
453    
454     /* reduce the damage, on average, 50%, and making things random. */
455    
456 root 1.18 dam = random_roll (1, abs (dam), victim, PREFER_LOW);
457 root 1.4 if (disease->stats.dam < 0)
458     dam = -dam;
459     new_symptom->stats.dam = dam;
460 root 1.2 }
461 elmex 1.1
462 root 1.4
463     new_symptom->stats.maxsp = disease->stats.maxsp;
464     new_symptom->stats.food = new_symptom->stats.maxgrace;
465    
466     new_symptom->name = new_symptom->name_pl = disease->name;
467    
468     new_symptom->level = disease->level;
469     new_symptom->speed = disease->speed;
470     new_symptom->value = 0;
471     new_symptom->stats.Str = disease->stats.Str;
472     new_symptom->stats.Dex = disease->stats.Dex;
473     new_symptom->stats.Con = disease->stats.Con;
474     new_symptom->stats.Wis = disease->stats.Wis;
475     new_symptom->stats.Int = disease->stats.Int;
476     new_symptom->stats.Pow = disease->stats.Pow;
477     new_symptom->stats.Cha = disease->stats.Cha;
478     new_symptom->stats.sp = disease->stats.sp;
479     new_symptom->stats.food = disease->last_eat;
480     new_symptom->stats.maxsp = disease->stats.maxsp;
481     new_symptom->last_sp = disease->last_sp;
482     new_symptom->stats.exp = 0;
483     new_symptom->stats.hp = disease->stats.hp;
484     new_symptom->msg = disease->msg;
485     new_symptom->attacktype = disease->attacktype;
486     new_symptom->other_arch = disease->other_arch;
487    
488 root 1.11 new_symptom->set_owner (disease->owner);
489 root 1.4
490     if (new_symptom->skill != disease->skill)
491     new_symptom->skill = disease->skill;
492    
493     new_symptom->move_block = 0;
494     insert_ob_in_ob (new_symptom, victim);
495     return 1;
496     }
497    
498     /* now deal with progressing diseases: we increase the debility
499     * caused by the symptoms.
500     */
501    
502     if (disease->stats.ac != 0)
503     {
504     float scale;
505    
506     symptom->value += disease->stats.ac;
507     scale = 1.0 + symptom->value / 100.0;
508     /* now rescale all the debilities */
509     symptom->stats.Str = (int) (scale * disease->stats.Str);
510     symptom->stats.Dex = (int) (scale * disease->stats.Dex);
511     symptom->stats.Con = (int) (scale * disease->stats.Con);
512     symptom->stats.Wis = (int) (scale * disease->stats.Wis);
513     symptom->stats.Int = (int) (scale * disease->stats.Int);
514     symptom->stats.Pow = (int) (scale * disease->stats.Pow);
515     symptom->stats.Cha = (int) (scale * disease->stats.Cha);
516     symptom->stats.dam = (int) (scale * disease->stats.dam);
517     symptom->stats.sp = (int) (scale * disease->stats.sp);
518     symptom->stats.food = (int) (scale * disease->last_eat);
519     symptom->stats.maxsp = (int) (scale * disease->stats.maxsp);
520     symptom->last_sp = (int) (scale * disease->last_sp);
521     symptom->stats.exp = 0;
522     symptom->stats.hp = (int) (scale * disease->stats.hp);
523     symptom->msg = disease->msg;
524     symptom->attacktype = disease->attacktype;
525     symptom->other_arch = disease->other_arch;
526 elmex 1.1 }
527 root 1.4 SET_FLAG (symptom, FLAG_APPLIED);
528 root 1.13 victim->update_stats ();
529 root 1.4 return 1;
530 elmex 1.1 }
531    
532    
533     /* grants immunity to plagues we've seen before. */
534 root 1.4 int
535     grant_immunity (object *disease)
536     {
537     object *immunity;
538 elmex 1.1 object *walk;
539 root 1.4
540 elmex 1.1 /* Don't give immunity to this disease if last_heal is set. */
541 root 1.4 if (disease->last_heal)
542     return 0;
543 elmex 1.1 /* first, search for an immunity of the same name */
544 root 1.4 for (walk = disease->env->inv; walk; walk = walk->below)
545     {
546 root 1.19 if (walk->type == 98 && disease->name == walk->name)
547 root 1.4 {
548     walk->level = disease->level;
549     return 1; /* just update the existing immunity. */
550     }
551     }
552     immunity = get_archetype ("immunity");
553 root 1.3 immunity->name = disease->name;
554 elmex 1.1 immunity->level = disease->level;
555     immunity->move_block = 0;
556 root 1.4 insert_ob_in_ob (immunity, disease->env);
557 elmex 1.1 return 1;
558    
559     }
560    
561    
562     /* make the symptom do the nasty things it does */
563    
564 root 1.4 int
565     move_symptom (object *symptom)
566     {
567     object *victim = symptom->env;
568     object *new_ob;
569     int sp_reduce;
570    
571     if (victim == NULL || victim->map == NULL)
572     { /* outside a monster/player, die immediately */
573 root 1.9 symptom->destroy ();
574 root 1.4 return 0;
575     }
576    
577     if (symptom->stats.dam > 0)
578     hit_player (victim, symptom->stats.dam, symptom, symptom->attacktype, 1);
579     else
580     hit_player (victim, (int) MAX (1, -victim->stats.maxhp * symptom->stats.dam / 100.0), symptom, symptom->attacktype, 1);
581    
582     if (symptom->stats.maxsp > 0)
583     sp_reduce = symptom->stats.maxsp;
584     else
585     sp_reduce = (int) MAX (1, victim->stats.maxsp * symptom->stats.maxsp / 100.0);
586     victim->stats.sp = MAX (0, victim->stats.sp - sp_reduce);
587    
588     /* create the symptom "other arch" object and drop it here
589     * under every part of the monster
590     * The victim may well have died.
591     */
592 elmex 1.1
593 root 1.4 if (victim->map == NULL)
594     return 0;
595     if (symptom->other_arch)
596     {
597     object *tmp;
598    
599     tmp = victim;
600     if (tmp->head != NULL)
601     tmp = tmp->head;
602 pippijn 1.15 for ( /*tmp initialised above */ ; tmp != NULL; tmp = tmp->more)
603 root 1.4 {
604     new_ob = arch_to_object (symptom->other_arch);
605     new_ob->x = tmp->x;
606     new_ob->y = tmp->y;
607     new_ob->map = victim->map;
608     insert_ob_in_map (new_ob, victim->map, victim, 0);
609 root 1.2 }
610 elmex 1.1 }
611 root 1.4 new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, symptom->msg);
612    
613     return 1;
614 elmex 1.1 }
615    
616    
617     /* possibly infect due to direct physical contact
618     i.e., AT_PHYSICAL-- called from "hit_player_attacktype" */
619    
620 root 1.4 int
621     check_physically_infect (object *victim, object *hitter)
622     {
623 elmex 1.1 object *walk;
624 root 1.4
625 elmex 1.1 /* search for diseases, give every disease a chance to infect */
626 root 1.4 for (walk = hitter->inv; walk != NULL; walk = walk->below)
627     if (walk->type == DISEASE)
628     infect_object (victim, walk, 0);
629 elmex 1.1 return 1;
630     }
631    
632     /* find a disease in someone*/
633 root 1.4 object *
634     find_disease (object *victim)
635     {
636 elmex 1.1 object *walk;
637 root 1.4
638     for (walk = victim->inv; walk; walk = walk->below)
639     if (walk->type == DISEASE)
640     return walk;
641 elmex 1.1 return NULL;
642     }
643 root 1.4
644 elmex 1.1 /* do the cure disease stuff, from the spell "cure disease" */
645    
646 root 1.4 int
647     cure_disease (object *sufferer, object *caster)
648     {
649     object *disease, *next;
650     int casting_level;
651     int cure = 0;
652    
653     if (caster)
654     casting_level = caster->level;
655     else
656     casting_level = 1000; /* if null caster, CURE all. */
657    
658     for (disease = sufferer->inv; disease; disease = next)
659     {
660     next = disease->below;
661    
662     if (disease->type == DISEASE)
663     { /* attempt to cure this disease */
664     /* If caster lvel is higher than disease level, cure chance
665     * is automatic. If lower, then the chance is basically
666     * 1 in level_diff - if there is a 5 level difference, chance
667     * is 1 in 5.
668     */
669     if ((casting_level >= disease->level) || (!(random_roll (0, (disease->level - casting_level - 1), caster, PREFER_LOW))))
670     {
671    
672     remove_symptoms (disease);
673     cure = 1;
674 root 1.9
675 root 1.4 if (caster)
676     change_exp (caster, disease->stats.exp, caster->chosen_skill ? &caster->chosen_skill->skill : (const char *) 0, 0);
677 root 1.9
678     disease->destroy ();
679 root 1.2 }
680     }
681 elmex 1.1 }
682 root 1.4 if (cure)
683     {
684     /* Only draw these messages once */
685     if (caster)
686     new_draw_info_format (NDI_UNIQUE, 0, caster, "You cure a disease!");
687     new_draw_info (NDI_UNIQUE, 0, sufferer, "You no longer feel diseased.");
688 elmex 1.1 }
689     return 1;
690     }
691    
692     /* reduces disease progression: reduce_symptoms
693     * return true if we actually reduce a disease.
694     */
695    
696 root 1.4 int
697     reduce_symptoms (object *sufferer, int reduction)
698     {
699     object *walk;
700     int success = 0;
701    
702     for (walk = sufferer->inv; walk; walk = walk->below)
703     {
704     if (walk->type == SYMPTOM)
705     {
706     if (walk->value > 0)
707     {
708     success = 1;
709     walk->value = MAX (0, walk->value - 2 * reduction);
710     /* give the disease time to modify this symptom,
711     * and reduce its severity. */
712     walk->speed_left = 0;
713 root 1.2 }
714 root 1.4 }
715 elmex 1.1 }
716 root 1.4 if (success)
717     new_draw_info (NDI_UNIQUE, 0, sufferer, "Your illness seems less severe.");
718     return success;
719 elmex 1.1 }