ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.53
Committed: Mon Oct 12 14:00:59 2009 UTC (14 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81
Changes since 1.52: +7 -6 lines
Log Message:
clarify license

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.43 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 pippijn 1.17 *
4 root 1.52 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.25 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.17 *
8 root 1.53 * Deliantra is free software: you can redistribute it and/or modify it under
9     * the terms of the Affero GNU General Public License as published by the
10     * Free Software Foundation, either version 3 of the License, or (at your
11     * 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.53 * You should have received a copy of the Affero GNU General Public License
19     * and the GNU General Public License along with this program. If not, see
20     * <http://www.gnu.org/licenses/>.
21 pippijn 1.17 *
22 root 1.43 * The authors can be reached via e-mail to <support@deliantra.net>
23 pippijn 1.17 */
24 elmex 1.1
25 root 1.21 /* This file contains all the code implementing diseases,
26     * except for odds and ends in attack.c and in
27     * living.c
28     */
29 elmex 1.1
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 root 1.35 last_sp^ Lethargy Percentage of max speed. 10 = 10% speed.
51 elmex 1.1
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 root 1.14 #include <sproto.h>
132 elmex 1.1 #include <spells.h>
133     #include <sounds.h>
134     #include <skills.h>
135    
136     /* IMPLEMENTATION NOTES
137 root 1.2
138     Diseases may be contageous. They are objects which exist in a player's
139 elmex 1.1 inventory. They themselves do nothing, except modify Symptoms, or
140     spread to other live objects. Symptoms are what actually damage the player:
141     these are their own object. */
142    
143 root 1.49 /* grants immunity to plagues we've seen before. */
144 root 1.4 static int
145 root 1.49 grant_immunity (object *disease)
146 elmex 1.1 {
147 root 1.49 object *immunity;
148     object *walk;
149    
150     /* Don't give immunity to this disease if last_heal is set. */
151     if (disease->last_heal)
152 root 1.4 return 0;
153 elmex 1.1
154 root 1.49 /* first, search for an immunity of the same name */
155     for (walk = disease->env->inv; walk; walk = walk->below)
156     if (walk->type == 98 && disease->name == walk->name)
157     {
158     walk->level = disease->level;
159     return 1; /* just update the existing immunity. */
160     }
161 root 1.40
162 root 1.49 immunity = get_archetype ("immunity");
163 elmex 1.1
164 root 1.49 immunity->name = disease->name;
165     immunity->level = disease->level;
166     immunity->move_block = 0;
167 elmex 1.1
168 root 1.49 insert_ob_in_ob (immunity, disease->env);
169 root 1.4
170 root 1.49 return 1;
171 elmex 1.1 }
172    
173 root 1.49 /* argument is a disease */
174     static object *
175     find_symptom (object *disease)
176 root 1.4 {
177 root 1.49 /* check the inventory for symptoms */
178     for (object *walk = disease->env->inv; walk; walk = walk->below)
179     if (walk->name == disease->name && walk->type == SYMPTOM)
180     return walk;
181 root 1.4
182 root 1.49 return NULL;
183 elmex 1.1 }
184    
185     /* remove any symptoms of disease
186     * Modified by MSW 2003-03-28 do try to find all the symptom the
187     * player may have - I think through some odd interactoins with
188     * disease level and player level and whatnot, a player could get
189     * more than one symtpom to a disease.
190     */
191 root 1.49 static int
192 root 1.4 remove_symptoms (object *disease)
193     {
194     object *symptom, *victim = NULL;
195    
196     while ((symptom = find_symptom (disease)) != NULL)
197     {
198     if (!victim)
199     victim = symptom->env;
200 root 1.9
201 root 1.48 symptom->destroy ();
202 root 1.4 }
203 root 1.9
204 root 1.4 if (victim)
205 root 1.13 victim->update_stats ();
206 root 1.30
207 root 1.4 return 0;
208 elmex 1.1 }
209    
210     /* searches around for more victims to infect */
211 root 1.49 static int
212 root 1.4 check_infection (object *disease)
213     {
214 root 1.39 int range = abs (disease->magic);
215 root 1.7
216 root 1.52 object *op = disease->outer_env_or_self ();
217 root 1.4
218 root 1.49 if (!op->is_on_map ())
219 root 1.4 return 0;
220 root 1.7
221 root 1.49 unordered_mapwalk (op, -range, -range, range, range)
222     {
223     mapspace &ms = m->at (nx, ny);
224 root 1.7
225 root 1.49 if (ms.flags () & P_IS_ALIVE)
226     for (object *tmp = ms.bot; tmp; tmp = tmp->above)
227     infect_object (tmp, disease, 0);
228     }
229 root 1.7
230 root 1.4 return 1;
231 elmex 1.1 }
232    
233 root 1.49 /* check if victim is susceptible to disease. */
234     static int
235     is_susceptible_to_disease (object *victim, object *disease)
236 root 1.4 {
237 root 1.49 if (!QUERY_FLAG (victim, FLAG_ALIVE))
238 root 1.4 return 0;
239    
240 root 1.49 if (victim->flag [FLAG_WIZ])
241 root 1.4 return 0;
242    
243 root 1.51 if (disease->race.contains ("*") && !QUERY_FLAG (victim, FLAG_UNDEAD))
244 root 1.49 return 1;
245 elmex 1.1
246 root 1.49 if ((disease->race == shstr_undead) && QUERY_FLAG (victim, FLAG_UNDEAD))
247     return 1;
248 root 1.4
249 root 1.51 if ((victim->race && disease->race.contains (victim->race)) || disease->race.contains (victim->name))
250 root 1.49 return 1;
251 root 1.4
252 root 1.49 return 0;
253 elmex 1.1 }
254    
255     /* this function monitors the symptoms caused by the disease (if any),
256     causes symptoms, and modifies existing symptoms in the case of
257     existing diseases. */
258 root 1.49 static int
259 root 1.4 do_symptoms (object *disease)
260     {
261     object *symptom;
262     object *victim;
263     object *tmp;
264    
265     victim = disease->env;
266    
267 root 1.30 if (!victim)
268     return 0; /* no-one to inflict symptoms on */
269    
270 root 1.4 /* This is a quick hack - for whatever reason, disease->env will point
271     * back to disease, causing endless loops. Why this happens really needs
272     * to be found, but this should at least prevent the infinite loops.
273     */
274 root 1.30 //TODO: should no longer be the case, monitor, and remove
275     if (victim == disease)
276     {
277     LOG (llevError | logBacktrace, "%s: disease->env points to itself", disease->debug_desc ());
278     return 0;
279     }
280 root 1.4
281     symptom = find_symptom (disease);
282 root 1.30 if (!symptom)
283 root 1.4 {
284     /* no symptom? need to generate one! */
285    
286     /* first check and see if the carrier of the disease is immune. If so, no symptoms! */
287     if (!is_susceptible_to_disease (victim, disease))
288     return 0;
289    
290     /* check for an actual immunity */
291     /* do an immunity check */
292 root 1.35 for (tmp = victim->head_ ()->inv; tmp; tmp = tmp->below)
293 root 1.30 if (tmp->type == SIGN) /* possibly an immunity, or diseased */
294     if (tmp->name == disease->name && tmp->level >= disease->level)
295 root 1.35 return 0; /* Immune! */
296 root 1.2
297 root 1.35 object *new_symptom = get_archetype ("symptom");
298 root 1.4
299     /* Something special done with dam. We want diseases to be more
300     * random in what they'll kill, so we'll make the damage they
301     * do random, note, this has a weird effect with progressive diseases.
302     */
303 root 1.35 if (disease->stats.dam)
304 root 1.4 {
305     int dam = disease->stats.dam;
306    
307     /* reduce the damage, on average, 50%, and making things random. */
308    
309 root 1.18 dam = random_roll (1, abs (dam), victim, PREFER_LOW);
310 root 1.4 if (disease->stats.dam < 0)
311     dam = -dam;
312 root 1.30
313 root 1.4 new_symptom->stats.dam = dam;
314 root 1.2 }
315 elmex 1.1
316 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
317 root 1.29 new_symptom->stats.food = new_symptom->stats.maxgrace;
318 root 1.4
319     new_symptom->name = new_symptom->name_pl = disease->name;
320    
321     new_symptom->level = disease->level;
322     new_symptom->speed = disease->speed;
323     new_symptom->value = 0;
324 root 1.22
325     for (int i = 0; i < NUM_STATS; ++i)
326     new_symptom->stats.stat (i) = disease->stats.stat (i);
327    
328 root 1.29 new_symptom->stats.sp = disease->stats.sp;
329     new_symptom->stats.food = disease->last_eat;
330 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
331 root 1.29 new_symptom->last_sp = disease->last_sp;
332     new_symptom->stats.exp = 0;
333     new_symptom->stats.hp = disease->stats.hp;
334     new_symptom->msg = disease->msg;
335     new_symptom->attacktype = disease->attacktype;
336     new_symptom->other_arch = disease->other_arch;
337 root 1.35 new_symptom->skill = disease->skill;
338    
339     new_symptom->move_block = 0;
340    
341     victim->head_ ()->insert (new_symptom);
342 root 1.4
343 root 1.36 // set owner last, as insert clears owner
344 root 1.11 new_symptom->set_owner (disease->owner);
345 root 1.4
346     return 1;
347     }
348    
349 root 1.23 /* now deal with progressing diseases: we increase the debility
350 root 1.4 * caused by the symptoms.
351     */
352 root 1.29 if (disease->stats.ac)
353 root 1.4 {
354 root 1.29 symptom->value = clamp (symptom->value + disease->stats.ac, 0, 100*100);
355 root 1.4
356 root 1.23 float scale = 1.f + symptom->value / 100.f;
357 root 1.22
358 root 1.4 /* now rescale all the debilities */
359 root 1.22 for (int i = 0; i < NUM_STATS; ++i)
360 root 1.31 symptom->stats.stat (i) = clamp (int (scale * disease->stats.stat (i)), -128, 127);
361 root 1.22
362 root 1.29 symptom->stats.dam = clamp (scale * disease->stats.dam , -1024, 1024);
363     symptom->stats.food = clamp (scale * disease->last_eat , -1024, 1024);
364     symptom->stats.maxsp = clamp (scale * disease->stats.maxsp, -1024, 1024);
365     symptom->stats.sp = clamp (scale * disease->stats.sp , -1024, 1024);
366     symptom->stats.hp = clamp (scale * disease->stats.hp , -1024, 1024);
367 root 1.22 symptom->stats.exp = 0;
368 root 1.33 symptom->last_sp = disease->last_sp ? clamp (disease->last_sp / scale, 1, 1024) : 0;
369 root 1.29 symptom->msg = disease->msg;
370     symptom->attacktype = disease->attacktype;
371     symptom->other_arch = disease->other_arch;
372 elmex 1.1 }
373 root 1.23
374 root 1.4 SET_FLAG (symptom, FLAG_APPLIED);
375 root 1.13 victim->update_stats ();
376 root 1.23
377 root 1.4 return 1;
378 elmex 1.1 }
379    
380 root 1.4 int
381 root 1.49 move_disease (object *disease)
382     {
383     /* First task is to determine if the disease is inside or outside of someone.
384     * If outside, we decrement 'value' until we're gone.
385     */
386    
387     if (!disease->env)
388     { /* we're outside of someone */
389     if (disease->stats.maxhp > 0)
390     disease->value--;
391    
392     if (!disease->value)
393     {
394     disease->destroy ();
395     return 1;
396     }
397     }
398     else
399     {
400     /* if we're inside a person, have the disease run its course */
401     /* negative/zero food denotes "perpetual" diseases. */
402     if (disease->stats.food > 0)
403     {
404     disease->stats.food--;
405    
406     if (!disease->stats.food)
407     {
408     remove_symptoms (disease); /* remove the symptoms of this disease */
409     grant_immunity (disease);
410     disease->destroy ();
411     return 1;
412     }
413     }
414     }
415    
416     /* check to see if we infect others */
417     check_infection (disease);
418    
419     /* impose or modify the symptoms of the disease */
420     if (disease->env && is_susceptible_to_disease (disease->env, disease))
421     do_symptoms (disease);
422    
423     return 0;
424     }
425    
426     /* check to see if an object is infectable:
427     * objects with immunity aren't infectable.
428     * objects already infected aren't infectable.
429     * dead objects aren't infectable.
430     * undead objects are infectible only if specifically named.
431     */
432     int
433     infect_object (object *victim, object *disease, int force)
434 root 1.4 {
435 root 1.49 object *tmp;
436     object *new_disease;
437    
438     /* don't infect inanimate objects */
439     if (!QUERY_FLAG (victim, FLAG_MONSTER) && !(victim->type == PLAYER))
440     return 0;
441    
442     /* check and see if victim can catch disease: diseases
443     * are specific
444     */
445     if (!is_susceptible_to_disease (victim, disease))
446     return 0;
447 root 1.4
448 root 1.49 /* roll the dice on infection before doing the inventory check! */
449     if (!force && (random_roll (0, 126, victim, PREFER_HIGH) >= disease->stats.wc))
450 root 1.4 return 0;
451 root 1.35
452 root 1.49 /* do an immunity check */
453    
454     /* There used to (IMO) be a flaw in the below - it used to be the case
455     * that if level check was done for both immunity and disease. This could
456     * result in a person with multiple afflictions of the same disease
457     * (eg, level 1 cold, level 2 cold, level 3 cold, etc), as long as
458     * they were cast in that same order. Instead, change it so that
459     * if you diseased, you can't get diseased more.
460     */
461    
462     for (tmp = victim->head_ ()->inv; tmp; tmp = tmp->below)
463     if (tmp->type == SIGN && tmp->name == disease->name && tmp->level >= disease->level)
464     return 0; /* Immune! */
465     else if (tmp->type == DISEASE && tmp->name == disease->name)
466     return 0; /* already diseased */
467    
468     /* If we've gotten this far, go ahead and infect the victim. */
469    
470     new_disease = disease->clone ();
471    
472     new_disease->stats.food = disease->stats.maxgrace;
473     new_disease->value = disease->stats.maxhp;
474     new_disease->stats.wc -= disease->last_grace; /* self-limiting factor */
475    
476     /* This appears to be a horrible case of overloading 'NO_PASS'
477     * for meaning in the diseases.
478     */
479     new_disease->move_block = 0;
480    
481     // insert before setting the owner
482     victim->head_ ()->insert (new_disease);
483    
484     if (disease->owner)
485     new_disease->set_owner (disease->owner);
486     else if (object *pl = disease->in_player ())
487     /* for diseases which are passed by hitting, set owner and skill */
488     new_disease->set_owner (pl);
489    
490     if (new_disease->owner && new_disease->owner->type == PLAYER)
491     {
492     const char *buf;
493 root 1.35
494 root 1.49 /* if the disease has a title, it has a special infection message
495     * This messages is printed in the form MESSAGE victim
496     */
497     if (new_disease->title)
498     buf = format ("%s %s!!", &disease->title, &victim->name);
499     else
500     buf = format ("You infect %s with your disease, %s!", &victim->name, &new_disease->name);
501 root 1.35
502 root 1.49 if (victim->type == PLAYER)
503     new_draw_info (NDI_UNIQUE | NDI_RED, 0, new_disease->owner, buf);
504     else
505     new_draw_info (0, 4, new_disease->owner, buf);
506     }
507 root 1.35
508 root 1.49 if (victim->type == PLAYER)
509     new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, "You suddenly feel ill.");
510 root 1.35
511 elmex 1.1 return 1;
512     }
513    
514     /* make the symptom do the nasty things it does */
515 root 1.4 int
516     move_symptom (object *symptom)
517     {
518     object *victim = symptom->env;
519     object *new_ob;
520     int sp_reduce;
521    
522 root 1.36 if (!victim || !victim->map)
523 root 1.4 { /* outside a monster/player, die immediately */
524 root 1.48 symptom->destroy ();
525 root 1.4 return 0;
526     }
527    
528     if (symptom->stats.dam > 0)
529     hit_player (victim, symptom->stats.dam, symptom, symptom->attacktype, 1);
530     else
531 root 1.45 hit_player (victim, max (1, -victim->stats.maxhp * symptom->stats.dam / 100), symptom, symptom->attacktype, 1);
532 root 1.4
533     if (symptom->stats.maxsp > 0)
534     sp_reduce = symptom->stats.maxsp;
535     else
536 root 1.45 sp_reduce = max (1, victim->stats.maxsp * symptom->stats.maxsp / 100);
537 root 1.35
538 root 1.37 victim->stats.sp = max (0, victim->stats.sp - sp_reduce);
539 root 1.4
540     /* create the symptom "other arch" object and drop it here
541     * under every part of the monster
542     * The victim may well have died.
543     */
544 root 1.42 if (victim->map)
545     {
546     victim->play_sound (symptom->sound);
547    
548     if (symptom->other_arch)
549     for (object *tmp = victim->head_ (); tmp; tmp = tmp->more)
550     {
551     new_ob = arch_to_object (symptom->other_arch);
552     new_ob->x = tmp->x;
553     new_ob->y = tmp->y;
554     new_ob->map = victim->map;
555     insert_ob_in_map (new_ob, victim->map, victim, 0);
556     }
557     }
558 root 1.4
559     new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, symptom->msg);
560    
561     return 1;
562 elmex 1.1 }
563    
564 root 1.20 /* possibly infect due to direct physical contact
565     * i.e., AT_PHYSICAL-- called from "hit_player_attacktype" */
566 root 1.4 int
567     check_physically_infect (object *victim, object *hitter)
568     {
569 root 1.20 /* search for diseases, give every disease a chance to infect */
570     for (object *disease = hitter->inv; disease; disease = disease->below)
571     if (disease->type == DISEASE)
572     infect_object (victim, disease, 0);
573 root 1.4
574 elmex 1.1 return 1;
575     }
576    
577 root 1.20 // find a disease in someone
578 root 1.4 object *
579     find_disease (object *victim)
580     {
581 root 1.20 for (object *disease = victim->inv; disease; disease = disease->below)
582     if (disease->type == DISEASE)
583     return disease;
584 root 1.4
585 root 1.20 return 0;
586 elmex 1.1 }
587 root 1.4
588 elmex 1.1 /* do the cure disease stuff, from the spell "cure disease" */
589 root 1.4 int
590 root 1.41 cure_disease (object *sufferer, object *caster, object *spell)
591 root 1.4 {
592     object *disease, *next;
593     int cure = 0;
594    
595 root 1.41 int casting_level = caster ? caster->level : 1000; /* if null caster, CURE all. */
596 root 1.4
597     for (disease = sufferer->inv; disease; disease = next)
598     {
599     next = disease->below;
600    
601     if (disease->type == DISEASE)
602     { /* attempt to cure this disease */
603 root 1.21 /* If caster level is higher than disease level, cure chance
604 root 1.4 * is automatic. If lower, then the chance is basically
605     * 1 in level_diff - if there is a 5 level difference, chance
606     * is 1 in 5.
607     */
608     if ((casting_level >= disease->level) || (!(random_roll (0, (disease->level - casting_level - 1), caster, PREFER_LOW))))
609     {
610     remove_symptoms (disease);
611     cure = 1;
612 root 1.9
613 root 1.41 if (caster && spell)
614     change_exp (caster, disease->stats.exp, spell->skill, SK_EXP_SKILL_ONLY);
615 root 1.9
616 root 1.48 disease->destroy ();
617 root 1.2 }
618     }
619 elmex 1.1 }
620 root 1.21
621 root 1.4 if (cure)
622     {
623     /* Only draw these messages once */
624     if (caster)
625     new_draw_info_format (NDI_UNIQUE, 0, caster, "You cure a disease!");
626 root 1.21
627 root 1.4 new_draw_info (NDI_UNIQUE, 0, sufferer, "You no longer feel diseased.");
628 elmex 1.1 }
629 root 1.21
630 elmex 1.1 return 1;
631     }
632    
633     /* reduces disease progression: reduce_symptoms
634     * return true if we actually reduce a disease.
635     */
636 root 1.4 int
637     reduce_symptoms (object *sufferer, int reduction)
638     {
639     object *walk;
640     int success = 0;
641    
642     for (walk = sufferer->inv; walk; walk = walk->below)
643     {
644     if (walk->type == SYMPTOM)
645     {
646     if (walk->value > 0)
647     {
648     success = 1;
649 root 1.29 walk->value = max (0, walk->value - 2 * reduction);
650 root 1.4 /* give the disease time to modify this symptom,
651     * and reduce its severity. */
652     walk->speed_left = 0;
653 root 1.2 }
654 root 1.4 }
655 elmex 1.1 }
656 root 1.29
657 root 1.4 if (success)
658     new_draw_info (NDI_UNIQUE, 0, sufferer, "Your illness seems less severe.");
659 root 1.29
660 root 1.4 return success;
661 elmex 1.1 }