ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.4
Committed: Sun Sep 10 15:59:57 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +466 -378 lines
Log Message:
indent

File Contents

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