ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.35
Committed: Mon Aug 20 19:13:10 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.34: +57 -89 lines
Log Message:
- hopefully fix say w.r.t. NDI_REPLY
- rework the disease code a bit.
- set_owene rfater inserting whne throwing or diseasing. these
  are the only cases i know where the owner is set when inserting into
  another object. *cough*

File Contents

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