ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.72
Committed: Wed Nov 16 23:42:02 2016 UTC (7 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.71: +1 -1 lines
Log Message:
copyright update 2016

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.43 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.71 *
4 root 1.72 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.62 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992 Frank Tore Johansen
7 root 1.71 *
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 root 1.71 *
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.71 *
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 root 1.71 *
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 root 1.70 * except for odds and ends in attack.c and in
27 root 1.21 * 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 root 1.70 magic+ Range range of infection
42 elmex 1.1 Stats* Disability What stats are reduced by the disease (str con...)
43 root 1.70 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 elmex 1.1
49 root 1.70 speed Speed How often the disease moves.
50     last_sp^ Lethargy Percentage of max speed. 10 = 10% speed.
51 elmex 1.1
52 root 1.70 maxsp^ Mana deplete Saps mana.
53 elmex 1.1 ac^ Progressiveness How the diseases increases in severity.
54 root 1.70 last_eat*^ Deplete food saps food if negative
55 elmex 1.1 last_heal GrantImmunity If nonzero, disease does NOT grant immunity
56 root 1.70 when it runs out
57 elmex 1.1
58 root 1.70 exp experience experience awarded when plague cured
59     hp*^ ReduceRegen reduces regeneration of disease-bearer
60     sp*^ ReduceSpRegen reduces spellpoint regeneration
61 elmex 1.1
62 root 1.70 name Name Name of the plague
63 elmex 1.1 msg message What the plague says when it strikes.
64 root 1.70 race those affected species/race the plague strikes (* = everything)
65 elmex 1.1 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     Explanations:
70     * means this # should be negative to cause adverse effect.
71     + means that this effect is modulated in spells by ldur
72     ^ means that this effect is modulated in spells by ldam
73    
74     attacktype is the attacktype used by the disease to smite "dam" damage with.
75    
76     wc/127 is the chance of someone in range catching it.
77    
78     magic is the range at which infection may occur. If negative, the range is
79     NOT level dependent.
80    
81     Stats are stat modifications. These should typically be negative.
82    
83     maxhp is how long the disease will persist if the host dies and "drops" it,
84     in "disease moves", i.e., moves of the disease. If negative, permanent.
85    
86    
87     value is the counter for maxhp, it starts at maxhp and drops...
88    
89     dam if positive, it is straight damage. if negative, a %-age.
90    
91     maxgrace how long in "disease moves" the disease lasts in the host, if negative,
92     permanent until cured.
93    
94     food if negative, disease is permanent. otherwise, decreases at <speed>,
95     disease goes away at food=0, set to "maxgrace" on infection.
96    
97     speed is the speed of the disease, how fast "disease moves" occur.
98    
99     last_sp is the lethargy imposed on the player by the disease. A lethargy
100     of "1" reduces the players speed to 1% of its normal value.
101    
102     maxsp how much mana is sapped per "disease move". if negative, a %-age is
103     taken.
104    
105     ac every "disease move" the severity of the symptoms are increased by
106     ac/100. (severity = 1 + (accumlated_progression)/100)
107    
108     last_eat increases food usage if negative.
109    
110    
111    
112     For SYMPTOMS:
113    
114     Stats modify stats
115     hp modify regen
116     value progression counter (multiplier = value/100)
117     food modify food use (from last_eat in DISEASE)
118     maxsp suck mana ( as noted for DISEASE)
119     last_sp Lethargy
120     msg What to say
121     speed speed of movement, from DISEASE
122    
123    
124     */
125    
126    
127     #include <global.h>
128     #include <object.h>
129     #include <living.h>
130 root 1.14 #include <sproto.h>
131 elmex 1.1 #include <spells.h>
132     #include <sounds.h>
133     #include <skills.h>
134    
135     /* IMPLEMENTATION NOTES
136 root 1.2
137     Diseases may be contageous. They are objects which exist in a player's
138 elmex 1.1 inventory. They themselves do nothing, except modify Symptoms, or
139     spread to other live objects. Symptoms are what actually damage the player:
140     these are their own object. */
141    
142 root 1.49 /* grants immunity to plagues we've seen before. */
143 root 1.4 static int
144 root 1.49 grant_immunity (object *disease)
145 elmex 1.1 {
146 root 1.49 object *immunity;
147     object *walk;
148    
149     /* Don't give immunity to this disease if last_heal is set. */
150     if (disease->last_heal)
151 root 1.4 return 0;
152 elmex 1.1
153 root 1.49 /* first, search for an immunity of the same name */
154     for (walk = disease->env->inv; walk; walk = walk->below)
155 root 1.64 if (disease->name == walk->name && walk->is_immunity ())
156 root 1.49 {
157     walk->level = disease->level;
158     return 1; /* just update the existing immunity. */
159     }
160 root 1.40
161 root 1.68 immunity = archetype::get (shstr_immunity);
162 elmex 1.1
163 root 1.49 immunity->name = disease->name;
164     immunity->level = disease->level;
165     immunity->move_block = 0;
166 elmex 1.1
167 root 1.49 insert_ob_in_ob (immunity, disease->env);
168 root 1.4
169 root 1.49 return 1;
170 elmex 1.1 }
171    
172 root 1.49 /* argument is a disease */
173     static object *
174     find_symptom (object *disease)
175 root 1.4 {
176 root 1.49 /* check the inventory for symptoms */
177     for (object *walk = disease->env->inv; walk; walk = walk->below)
178     if (walk->name == disease->name && walk->type == SYMPTOM)
179     return walk;
180 root 1.4
181 root 1.49 return NULL;
182 elmex 1.1 }
183    
184     /* remove any symptoms of disease
185     * Modified by MSW 2003-03-28 do try to find all the symptom the
186     * player may have - I think through some odd interactoins with
187     * disease level and player level and whatnot, a player could get
188     * more than one symtpom to a disease.
189     */
190 root 1.49 static int
191 root 1.4 remove_symptoms (object *disease)
192     {
193     object *symptom, *victim = NULL;
194    
195     while ((symptom = find_symptom (disease)) != NULL)
196     {
197     if (!victim)
198     victim = symptom->env;
199 root 1.9
200 root 1.48 symptom->destroy ();
201 root 1.4 }
202 root 1.9
203 root 1.4 if (victim)
204 root 1.13 victim->update_stats ();
205 root 1.30
206 root 1.4 return 0;
207 elmex 1.1 }
208    
209     /* searches around for more victims to infect */
210 root 1.49 static int
211 root 1.4 check_infection (object *disease)
212     {
213 root 1.39 int range = abs (disease->magic);
214 root 1.7
215 root 1.52 object *op = disease->outer_env_or_self ();
216 root 1.4
217 root 1.49 if (!op->is_on_map ())
218 root 1.4 return 0;
219 root 1.7
220 root 1.61 dynbuf buf;
221     unordered_mapwalk (buf, op, -range, -range, range, range)
222 root 1.49 {
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.65 if (!victim->flag [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.65 if (disease->race.contains ("*") && !victim->flag [FLAG_UNDEAD])
244 root 1.49 return 1;
245 elmex 1.1
246 root 1.65 if ((disease->race == shstr_undead) && victim->flag [FLAG_UNDEAD])
247 root 1.49 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.64 if (tmp->name == disease->name && tmp->is_immunity ()) /* possibly an immunity, or diseased */
294     if (tmp->level >= disease->level)
295 root 1.35 return 0; /* Immune! */
296 root 1.2
297 root 1.68 object *new_symptom = archetype::get (shstr_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->value = 0;
323 root 1.22
324 root 1.66 new_symptom->set_speed (disease->speed);
325    
326 root 1.22 for (int i = 0; i < NUM_STATS; ++i)
327     new_symptom->stats.stat (i) = disease->stats.stat (i);
328    
329 root 1.29 new_symptom->stats.sp = disease->stats.sp;
330     new_symptom->stats.food = disease->last_eat;
331 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
332 root 1.29 new_symptom->last_sp = disease->last_sp;
333     new_symptom->stats.exp = 0;
334     new_symptom->stats.hp = disease->stats.hp;
335     new_symptom->msg = disease->msg;
336     new_symptom->attacktype = disease->attacktype;
337     new_symptom->other_arch = disease->other_arch;
338 root 1.35 new_symptom->skill = disease->skill;
339    
340     new_symptom->move_block = 0;
341    
342     victim->head_ ()->insert (new_symptom);
343 root 1.4
344 root 1.36 // set owner last, as insert clears owner
345 root 1.11 new_symptom->set_owner (disease->owner);
346 root 1.4
347     return 1;
348     }
349    
350 root 1.23 /* now deal with progressing diseases: we increase the debility
351 root 1.4 * caused by the symptoms.
352     */
353 root 1.29 if (disease->stats.ac)
354 root 1.4 {
355 root 1.29 symptom->value = clamp (symptom->value + disease->stats.ac, 0, 100*100);
356 root 1.4
357 root 1.23 float scale = 1.f + symptom->value / 100.f;
358 root 1.22
359 root 1.4 /* now rescale all the debilities */
360 root 1.22 for (int i = 0; i < NUM_STATS; ++i)
361 root 1.31 symptom->stats.stat (i) = clamp (int (scale * disease->stats.stat (i)), -128, 127);
362 root 1.22
363 root 1.29 symptom->stats.dam = clamp (scale * disease->stats.dam , -1024, 1024);
364     symptom->stats.food = clamp (scale * disease->last_eat , -1024, 1024);
365     symptom->stats.maxsp = clamp (scale * disease->stats.maxsp, -1024, 1024);
366     symptom->stats.sp = clamp (scale * disease->stats.sp , -1024, 1024);
367     symptom->stats.hp = clamp (scale * disease->stats.hp , -1024, 1024);
368 root 1.22 symptom->stats.exp = 0;
369 root 1.33 symptom->last_sp = disease->last_sp ? clamp (disease->last_sp / scale, 1, 1024) : 0;
370 root 1.29 symptom->msg = disease->msg;
371     symptom->attacktype = disease->attacktype;
372     symptom->other_arch = disease->other_arch;
373 elmex 1.1 }
374 root 1.23
375 root 1.65 symptom->set_flag (FLAG_APPLIED);
376 root 1.13 victim->update_stats ();
377 root 1.23
378 root 1.4 return 1;
379 elmex 1.1 }
380    
381 root 1.4 int
382 root 1.49 move_disease (object *disease)
383     {
384     /* First task is to determine if the disease is inside or outside of someone.
385     * If outside, we decrement 'value' until we're gone.
386     */
387    
388     if (!disease->env)
389     { /* we're outside of someone */
390     if (disease->stats.maxhp > 0)
391     disease->value--;
392    
393     if (!disease->value)
394     {
395     disease->destroy ();
396     return 1;
397     }
398     }
399     else
400     {
401     /* if we're inside a person, have the disease run its course */
402     /* negative/zero food denotes "perpetual" diseases. */
403     if (disease->stats.food > 0)
404     {
405     disease->stats.food--;
406    
407     if (!disease->stats.food)
408     {
409     remove_symptoms (disease); /* remove the symptoms of this disease */
410     grant_immunity (disease);
411     disease->destroy ();
412     return 1;
413     }
414     }
415     }
416    
417     /* check to see if we infect others */
418     check_infection (disease);
419    
420     /* impose or modify the symptoms of the disease */
421     if (disease->env && is_susceptible_to_disease (disease->env, disease))
422     do_symptoms (disease);
423    
424     return 0;
425     }
426    
427     /* check to see if an object is infectable:
428     * objects with immunity aren't infectable.
429     * objects already infected aren't infectable.
430     * dead objects aren't infectable.
431     * undead objects are infectible only if specifically named.
432     */
433     int
434     infect_object (object *victim, object *disease, int force)
435 root 1.4 {
436 root 1.49 object *tmp;
437     object *new_disease;
438    
439     /* don't infect inanimate objects */
440 root 1.65 if (!victim->flag [FLAG_MONSTER] && !(victim->type == PLAYER))
441 root 1.49 return 0;
442    
443     /* check and see if victim can catch disease: diseases
444     * are specific
445     */
446     if (!is_susceptible_to_disease (victim, disease))
447     return 0;
448 root 1.4
449 root 1.49 /* roll the dice on infection before doing the inventory check! */
450     if (!force && (random_roll (0, 126, victim, PREFER_HIGH) >= disease->stats.wc))
451 root 1.4 return 0;
452 root 1.35
453 root 1.49 /* do an immunity check */
454    
455     /* There used to (IMO) be a flaw in the below - it used to be the case
456     * that if level check was done for both immunity and disease. This could
457     * result in a person with multiple afflictions of the same disease
458     * (eg, level 1 cold, level 2 cold, level 3 cold, etc), as long as
459     * they were cast in that same order. Instead, change it so that
460     * if you diseased, you can't get diseased more.
461     */
462    
463     for (tmp = victim->head_ ()->inv; tmp; tmp = tmp->below)
464 root 1.64 if (tmp->name == disease->name && tmp->is_immunity () && tmp->level >= disease->level)
465 root 1.49 return 0; /* Immune! */
466     else if (tmp->type == DISEASE && tmp->name == disease->name)
467     return 0; /* already diseased */
468    
469     /* If we've gotten this far, go ahead and infect the victim. */
470    
471     new_disease = disease->clone ();
472    
473     new_disease->stats.food = disease->stats.maxgrace;
474     new_disease->value = disease->stats.maxhp;
475     new_disease->stats.wc -= disease->last_grace; /* self-limiting factor */
476    
477     /* This appears to be a horrible case of overloading 'NO_PASS'
478     * for meaning in the diseases.
479     */
480     new_disease->move_block = 0;
481    
482     // insert before setting the owner
483     victim->head_ ()->insert (new_disease);
484    
485     if (disease->owner)
486     new_disease->set_owner (disease->owner);
487     else if (object *pl = disease->in_player ())
488     /* for diseases which are passed by hitting, set owner and skill */
489     new_disease->set_owner (pl);
490    
491 root 1.70 if (INVOKE_OBJECT (INFECT, victim, ARG_OBJECT (disease), ARG_OBJECT (new_disease)))
492     return 1;
493    
494 root 1.49 if (new_disease->owner && new_disease->owner->type == PLAYER)
495     {
496     const char *buf;
497 root 1.35
498 root 1.49 /* if the disease has a title, it has a special infection message
499     * This messages is printed in the form MESSAGE victim
500     */
501     if (new_disease->title)
502     buf = format ("%s %s!!", &disease->title, &victim->name);
503     else
504     buf = format ("You infect %s with your disease, %s!", &victim->name, &new_disease->name);
505 root 1.35
506 root 1.49 if (victim->type == PLAYER)
507     new_draw_info (NDI_UNIQUE | NDI_RED, 0, new_disease->owner, buf);
508     else
509     new_draw_info (0, 4, new_disease->owner, buf);
510     }
511 root 1.35
512 root 1.49 if (victim->type == PLAYER)
513     new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, "You suddenly feel ill.");
514 root 1.35
515 elmex 1.1 return 1;
516     }
517    
518     /* make the symptom do the nasty things it does */
519 root 1.4 int
520     move_symptom (object *symptom)
521     {
522     object *victim = symptom->env;
523    
524 root 1.36 if (!victim || !victim->map)
525 root 1.4 { /* outside a monster/player, die immediately */
526 root 1.48 symptom->destroy ();
527 root 1.4 return 0;
528     }
529    
530     /* create the symptom "other arch" object and drop it here
531     * under every part of the monster
532     * The victim may well have died.
533     */
534 root 1.42 if (victim->map)
535     {
536     victim->play_sound (symptom->sound);
537    
538     if (symptom->other_arch)
539     for (object *tmp = victim->head_ (); tmp; tmp = tmp->more)
540     {
541 root 1.60 object *new_ob = symptom->other_arch->instance ();
542 root 1.42 new_ob->x = tmp->x;
543     new_ob->y = tmp->y;
544     new_ob->map = victim->map;
545     insert_ob_in_map (new_ob, victim->map, victim, 0);
546     }
547     }
548 root 1.4
549 root 1.59 int damage =
550     symptom->stats.dam > 0
551     ? symptom->stats.dam
552     : max (1, victim->stats.maxhp * -symptom->stats.dam / 100);
553    
554     hit_player (victim, damage, symptom, symptom->attacktype, 1);
555    
556     int sp_reduce =
557     symptom->stats.maxsp > 0
558     ? symptom->stats.maxsp
559     : max (1, victim->stats.maxsp * -symptom->stats.maxsp / 100);
560    
561     victim->stats.sp = max (0, victim->stats.sp - sp_reduce);
562    
563 root 1.4 new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, symptom->msg);
564    
565     return 1;
566 elmex 1.1 }
567    
568 root 1.20 /* possibly infect due to direct physical contact
569     * i.e., AT_PHYSICAL-- called from "hit_player_attacktype" */
570 root 1.4 int
571     check_physically_infect (object *victim, object *hitter)
572     {
573 root 1.20 /* search for diseases, give every disease a chance to infect */
574     for (object *disease = hitter->inv; disease; disease = disease->below)
575     if (disease->type == DISEASE)
576     infect_object (victim, disease, 0);
577 root 1.4
578 elmex 1.1 return 1;
579     }
580    
581     /* do the cure disease stuff, from the spell "cure disease" */
582 root 1.4 int
583 root 1.41 cure_disease (object *sufferer, object *caster, object *spell)
584 root 1.4 {
585     object *disease, *next;
586     int cure = 0;
587    
588 root 1.41 int casting_level = caster ? caster->level : 1000; /* if null caster, CURE all. */
589 root 1.4
590     for (disease = sufferer->inv; disease; disease = next)
591     {
592     next = disease->below;
593    
594     if (disease->type == DISEASE)
595     { /* attempt to cure this disease */
596 root 1.21 /* If caster level is higher than disease level, cure chance
597 root 1.4 * is automatic. If lower, then the chance is basically
598     * 1 in level_diff - if there is a 5 level difference, chance
599     * is 1 in 5.
600     */
601     if ((casting_level >= disease->level) || (!(random_roll (0, (disease->level - casting_level - 1), caster, PREFER_LOW))))
602     {
603     remove_symptoms (disease);
604     cure = 1;
605 root 1.9
606 root 1.41 if (caster && spell)
607     change_exp (caster, disease->stats.exp, spell->skill, SK_EXP_SKILL_ONLY);
608 root 1.9
609 root 1.48 disease->destroy ();
610 root 1.2 }
611     }
612 elmex 1.1 }
613 root 1.21
614 root 1.4 if (cure)
615     {
616     /* Only draw these messages once */
617     if (caster)
618     new_draw_info_format (NDI_UNIQUE, 0, caster, "You cure a disease!");
619 root 1.21
620 root 1.4 new_draw_info (NDI_UNIQUE, 0, sufferer, "You no longer feel diseased.");
621 elmex 1.1 }
622 root 1.21
623 elmex 1.1 return 1;
624     }
625    
626 root 1.56 #if 0 // unused, but seems interesting
627 elmex 1.1 /* reduces disease progression: reduce_symptoms
628     * return true if we actually reduce a disease.
629     */
630 root 1.55 static int
631 root 1.4 reduce_symptoms (object *sufferer, int reduction)
632     {
633     object *walk;
634     int success = 0;
635    
636     for (walk = sufferer->inv; walk; walk = walk->below)
637     {
638     if (walk->type == SYMPTOM)
639     {
640     if (walk->value > 0)
641     {
642     success = 1;
643 root 1.29 walk->value = max (0, walk->value - 2 * reduction);
644 root 1.4 /* give the disease time to modify this symptom,
645     * and reduce its severity. */
646     walk->speed_left = 0;
647 root 1.2 }
648 root 1.4 }
649 elmex 1.1 }
650 root 1.29
651 root 1.4 if (success)
652     new_draw_info (NDI_UNIQUE, 0, sufferer, "Your illness seems less severe.");
653 root 1.29
654 root 1.4 return success;
655 elmex 1.1 }
656 root 1.56 #endif