ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.7
Committed: Thu Oct 5 16:50:07 2006 UTC (17 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +18 -20 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5     Copyright (C) 1992 Frank Tore Johansen
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 root 1.5 The authors can be reached via e-mail to <crossfire@schmorp.de>
22 elmex 1.1 */
23    
24     /* This file contains all the code implementing diseases,
25     except for odds and ends in attack.c and in
26 root 1.2 living.c*/
27 elmex 1.1
28    
29    
30     /*
31    
32     For DISEASES:
33     Stat Property Definition
34    
35     attacktype Attack effects Attacktype of the disease. usu. AT_GODPOWER.
36     other_arch Creation object created and dropped when symptom moved.
37     title Message When the "disease" "infects" something, it will
38     print "title victim!!!" to the player who owns
39 root 1.2 the "disease".
40 elmex 1.1 wc+ Infectiousness How well the plague spreads person-to-person
41     magic+ Range range of infection
42     Stats* Disability What stats are reduced by the disease (str con...)
43     maxhp+ Persistence How long the disease can last OUTSIDE the host.
44     value TimeLeft Counter for persistence
45     dam^ Damage How much damage it does (%?).
46     maxgrace+ Duration How long before the disease is naturally cured.
47     food DurCount Counter for Duration
48    
49     speed Speed How often the disease moves.
50     last_sp^ Lethargy Percentage of max speed--10 = 10% speed.
51    
52     maxsp^ Mana deplete Saps mana.
53     ac^ Progressiveness How the diseases increases in severity.
54     last_eat*^ Deplete food saps food if negative
55     last_heal GrantImmunity If nonzero, disease does NOT grant immunity
56     when it runs out
57    
58     exp experience experience awarded when plague cured
59     hp*^ ReduceRegen reduces regeneration of disease-bearer
60     sp*^ ReduceSpRegen reduces spellpoint regeneration
61    
62     name Name Name of the plague
63     msg message What the plague says when it strikes.
64     race those affected species/race the plague strikes (* = everything)
65     level Plague Level General description of the plague's deadliness
66     armour Attenuation reduction in wc per generation of disease.
67     This builds in a self-limiting factor.
68    
69    
70     Explanations:
71     * means this # should be negative to cause adverse effect.
72     + means that this effect is modulated in spells by ldur
73     ^ means that this effect is modulated in spells by ldam
74    
75     attacktype is the attacktype used by the disease to smite "dam" damage with.
76    
77     wc/127 is the chance of someone in range catching it.
78    
79     magic is the range at which infection may occur. If negative, the range is
80     NOT level dependent.
81    
82     Stats are stat modifications. These should typically be negative.
83    
84     maxhp is how long the disease will persist if the host dies and "drops" it,
85     in "disease moves", i.e., moves of the disease. If negative, permanent.
86    
87    
88     value is the counter for maxhp, it starts at maxhp and drops...
89    
90     dam if positive, it is straight damage. if negative, a %-age.
91    
92     maxgrace how long in "disease moves" the disease lasts in the host, if negative,
93     permanent until cured.
94    
95     food if negative, disease is permanent. otherwise, decreases at <speed>,
96     disease goes away at food=0, set to "maxgrace" on infection.
97    
98     speed is the speed of the disease, how fast "disease moves" occur.
99    
100     last_sp is the lethargy imposed on the player by the disease. A lethargy
101     of "1" reduces the players speed to 1% of its normal value.
102    
103     maxsp how much mana is sapped per "disease move". if negative, a %-age is
104     taken.
105    
106     ac every "disease move" the severity of the symptoms are increased by
107     ac/100. (severity = 1 + (accumlated_progression)/100)
108    
109     last_eat increases food usage if negative.
110    
111    
112    
113     For SYMPTOMS:
114    
115     Stats modify stats
116     hp modify regen
117     value progression counter (multiplier = value/100)
118     food modify food use (from last_eat in DISEASE)
119     maxsp suck mana ( as noted for DISEASE)
120     last_sp Lethargy
121     msg What to say
122     speed speed of movement, from DISEASE
123    
124    
125     */
126    
127    
128     #include <global.h>
129     #include <object.h>
130     #include <living.h>
131     #ifndef __CEXTRACT__
132 root 1.4 # include <sproto.h>
133 elmex 1.1 #endif
134     #include <spells.h>
135     #include <sounds.h>
136     #include <skills.h>
137    
138     /* IMPLEMENTATION NOTES
139 root 1.2
140     Diseases may be contageous. They are objects which exist in a player's
141 elmex 1.1 inventory. They themselves do nothing, except modify Symptoms, or
142     spread to other live objects. Symptoms are what actually damage the player:
143     these are their own object. */
144    
145     /* check if victim is susceptible to disease. */
146 root 1.4 static int
147     is_susceptible_to_disease (object *victim, object *disease)
148 elmex 1.1 {
149 root 1.4 if (!QUERY_FLAG (victim, FLAG_ALIVE))
150     return 0;
151 elmex 1.1
152 root 1.4 if (strstr (disease->race, "*") && !QUERY_FLAG (victim, FLAG_UNDEAD))
153     return 1;
154 elmex 1.1
155 root 1.4 if ((disease->race == undead_name) && QUERY_FLAG (victim, FLAG_UNDEAD))
156     return 1;
157 elmex 1.1
158 root 1.4 if ((victim->race && strstr (disease->race, victim->race)) || strstr (disease->race, victim->name))
159     return 1;
160    
161     return 0;
162 elmex 1.1 }
163    
164 root 1.4 int
165     move_disease (object *disease)
166     {
167     /* first task is to determine if the disease is inside or outside of someone.
168     * If outside, we decrement 'value' until we're gone.
169     */
170    
171     if (disease->env == NULL)
172     { /* we're outside of someone */
173     if (disease->stats.maxhp > 0)
174     disease->value--;
175     if (disease->value == 0)
176     {
177     remove_ob (disease);
178     free_object (disease);
179     return 1;
180 root 1.2 }
181 root 1.4 }
182     else
183     {
184     /* if we're inside a person, have the disease run its course */
185     /* negative foods denote "perpetual" diseases. */
186     if (disease->stats.food > 0)
187     {
188     disease->stats.food--;
189     if (disease->stats.food == 0)
190     {
191     remove_symptoms (disease); /* remove the symptoms of this disease */
192     grant_immunity (disease);
193     remove_ob (disease);
194     free_object (disease);
195     return 1;
196 root 1.2 }
197     }
198 elmex 1.1 }
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     remove_ob (symptom);
226     free_object (symptom);
227     }
228     if (victim)
229     fix_player (victim);
230     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     if (!strcmp (walk->name, disease->name) && walk->type == SYMPTOM)
242     return walk;
243 elmex 1.1 return NULL;
244     }
245 root 1.4
246 elmex 1.1 /* searches around for more victims to infect */
247 root 1.4 int
248     check_infection (object *disease)
249     {
250     int x, y, range, mflags;
251 root 1.6 maptile *map, *map2;
252 root 1.4 object *tmp;
253    
254     range = abs (disease->magic);
255 root 1.7
256 root 1.4 if (disease->env)
257     {
258 root 1.7 x = disease->env->x;
259     y = disease->env->y;
260 root 1.4 map = disease->env->map;
261     }
262     else
263     {
264 root 1.7 x = disease->x;
265     y = disease->y;
266 root 1.4 map = disease->map;
267     }
268    
269 root 1.7 if (!map)
270 root 1.4 return 0;
271 root 1.7
272     for (int i = x - range; i <= x + range; i++)
273     for (int j = y - range; j <= y + range; j++)
274     {
275     sint16 i2, j2;
276     mflags = get_map_flags (map, &map2, i, j, &i2, &j2);
277    
278     if (!(mflags & P_OUT_OF_MAP) && (mflags & P_IS_ALIVE))
279     for (tmp = get_map_ob (map2, i2, j2); tmp; tmp = tmp->above)
280     infect_object (tmp, disease, 0);
281     }
282    
283 root 1.4 return 1;
284 elmex 1.1 }
285    
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     for ( /* tmp initialized in if, above */ ; tmp; tmp = tmp->below)
328     {
329     if (tmp->type == SIGN && !strcmp (tmp->name, disease->name) && tmp->level >= disease->level)
330     return 0; /*Immune! */
331     else if (tmp->type == DISEASE && !strcmp (tmp->name, disease->name))
332     return 0; /* already diseased */
333     }
334    
335     /* If we've gotten this far, go ahead and infect the victim. */
336     new_disease = get_object ();
337     copy_object (disease, new_disease);
338     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     if (get_owner (disease))
347     {
348     set_owner (new_disease, disease->owner);
349    
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     set_owner (new_disease, player);
361    
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     for ( /* tmp initialized in if, above */ ; tmp; tmp = tmp->below)
438     {
439     if (tmp->type == SIGN) /* possibly an immunity, or diseased */
440     if (!strcmp (tmp->name, disease->name) && tmp->level >= disease->level)
441     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     dam = random_roll (1, FABS (dam), victim, PREFER_LOW);
457     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     set_owner (new_symptom, disease->owner);
489    
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     fix_player (victim);
529     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     if (walk->type == 98 && !strcmp (disease->name, walk->name))
547     {
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     remove_ob (symptom);
574     free_object (symptom);
575     return 0;
576     }
577    
578     if (symptom->stats.dam > 0)
579     hit_player (victim, symptom->stats.dam, symptom, symptom->attacktype, 1);
580     else
581     hit_player (victim, (int) MAX (1, -victim->stats.maxhp * symptom->stats.dam / 100.0), symptom, symptom->attacktype, 1);
582    
583     if (symptom->stats.maxsp > 0)
584     sp_reduce = symptom->stats.maxsp;
585     else
586     sp_reduce = (int) MAX (1, victim->stats.maxsp * symptom->stats.maxsp / 100.0);
587     victim->stats.sp = MAX (0, victim->stats.sp - sp_reduce);
588    
589     /* create the symptom "other arch" object and drop it here
590     * under every part of the monster
591     * The victim may well have died.
592     */
593 elmex 1.1
594 root 1.4 if (victim->map == NULL)
595     return 0;
596     if (symptom->other_arch)
597     {
598     object *tmp;
599    
600     tmp = victim;
601     if (tmp->head != NULL)
602     tmp = tmp->head;
603     for ( /*tmp initialized above */ ; tmp != NULL; tmp = tmp->more)
604     {
605     new_ob = arch_to_object (symptom->other_arch);
606     new_ob->x = tmp->x;
607     new_ob->y = tmp->y;
608     new_ob->map = victim->map;
609     insert_ob_in_map (new_ob, victim->map, victim, 0);
610 root 1.2 }
611 elmex 1.1 }
612 root 1.4 new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, symptom->msg);
613    
614     return 1;
615 elmex 1.1 }
616    
617    
618     /* possibly infect due to direct physical contact
619     i.e., AT_PHYSICAL-- called from "hit_player_attacktype" */
620    
621 root 1.4 int
622     check_physically_infect (object *victim, object *hitter)
623     {
624 elmex 1.1 object *walk;
625 root 1.4
626 elmex 1.1 /* search for diseases, give every disease a chance to infect */
627 root 1.4 for (walk = hitter->inv; walk != NULL; walk = walk->below)
628     if (walk->type == DISEASE)
629     infect_object (victim, walk, 0);
630 elmex 1.1 return 1;
631     }
632    
633     /* find a disease in someone*/
634 root 1.4 object *
635     find_disease (object *victim)
636     {
637 elmex 1.1 object *walk;
638 root 1.4
639     for (walk = victim->inv; walk; walk = walk->below)
640     if (walk->type == DISEASE)
641     return walk;
642 elmex 1.1 return NULL;
643     }
644 root 1.4
645 elmex 1.1 /* do the cure disease stuff, from the spell "cure disease" */
646    
647 root 1.4 int
648     cure_disease (object *sufferer, object *caster)
649     {
650     object *disease, *next;
651     int casting_level;
652     int cure = 0;
653    
654     if (caster)
655     casting_level = caster->level;
656     else
657     casting_level = 1000; /* if null caster, CURE all. */
658    
659     for (disease = sufferer->inv; disease; disease = next)
660     {
661     next = disease->below;
662    
663     if (disease->type == DISEASE)
664     { /* attempt to cure this disease */
665     /* If caster lvel is higher than disease level, cure chance
666     * is automatic. If lower, then the chance is basically
667     * 1 in level_diff - if there is a 5 level difference, chance
668     * is 1 in 5.
669     */
670     if ((casting_level >= disease->level) || (!(random_roll (0, (disease->level - casting_level - 1), caster, PREFER_LOW))))
671     {
672    
673     remove_symptoms (disease);
674     remove_ob (disease);
675     cure = 1;
676     if (caster)
677     change_exp (caster, disease->stats.exp, caster->chosen_skill ? &caster->chosen_skill->skill : (const char *) 0, 0);
678     free_object (disease);
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 }