ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/disease.C
Revision: 1.47
Committed: Mon Sep 29 10:20:49 2008 UTC (15 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.46: +6 -6 lines
Log Message:
do the same everywhere else

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.46 * Copyright (©) 2005,2006,2007,2008 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.43 * Deliantra is free software: you can redistribute it and/or modify
9 root 1.27 * 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 root 1.43 * The authors can be reached via e-mail to <support@deliantra.net>
22 pippijn 1.17 */
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.40 if (victim->flag [FLAG_WIZ])
150     return 0;
151    
152 root 1.4 if (strstr (disease->race, "*") && !QUERY_FLAG (victim, FLAG_UNDEAD))
153     return 1;
154 elmex 1.1
155 root 1.28 if ((disease->race == shstr_undead) && QUERY_FLAG (victim, FLAG_UNDEAD))
156 root 1.4 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 root 1.47 /* First task is to determine if the disease is inside or outside of someone.
168 root 1.4 * If outside, we decrement 'value' until we're gone.
169     */
170    
171 root 1.29 if (!disease->env)
172 root 1.4 { /* we're outside of someone */
173     if (disease->stats.maxhp > 0)
174     disease->value--;
175 root 1.9
176 root 1.29 if (!disease->value)
177 root 1.4 {
178 root 1.47 disease->destroy (true);
179 root 1.4 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 root 1.29 /* negative/zero food denotes "perpetual" diseases. */
186 root 1.4 if (disease->stats.food > 0)
187     {
188     disease->stats.food--;
189 root 1.9
190 root 1.29 if (!disease->stats.food)
191 root 1.4 {
192     remove_symptoms (disease); /* remove the symptoms of this disease */
193     grant_immunity (disease);
194 root 1.47 disease->destroy (true);
195 root 1.4 return 1;
196 root 1.2 }
197     }
198 elmex 1.1 }
199 root 1.9
200 root 1.4 /* check to see if we infect others */
201     check_infection (disease);
202 elmex 1.1
203 root 1.4 /* impose or modify the symptoms of the disease */
204     if (disease->env && is_susceptible_to_disease (disease->env, disease))
205     do_symptoms (disease);
206 elmex 1.1
207 root 1.4 return 0;
208 elmex 1.1 }
209    
210     /* remove any symptoms of disease
211     * Modified by MSW 2003-03-28 do try to find all the symptom the
212     * player may have - I think through some odd interactoins with
213     * disease level and player level and whatnot, a player could get
214     * more than one symtpom to a disease.
215     */
216 root 1.4 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 root 1.9
226 root 1.47 symptom->destroy (true);
227 root 1.4 }
228 root 1.9
229 root 1.4 if (victim)
230 root 1.13 victim->update_stats ();
231 root 1.30
232 root 1.4 return 0;
233 elmex 1.1 }
234    
235     /* argument is a disease */
236 root 1.4 object *
237     find_symptom (object *disease)
238     {
239 elmex 1.1 /* check the inventory for symptoms */
240 root 1.35 for (object *walk = disease->env->inv; walk; walk = walk->below)
241 root 1.19 if (walk->name == disease->name && walk->type == SYMPTOM)
242 root 1.4 return walk;
243 root 1.30
244 elmex 1.1 return NULL;
245     }
246 root 1.4
247 elmex 1.1 /* searches around for more victims to infect */
248 root 1.4 int
249     check_infection (object *disease)
250     {
251 root 1.39 int x, y;
252 root 1.6 maptile *map, *map2;
253 root 1.4 object *tmp;
254    
255 root 1.39 int range = abs (disease->magic);
256 root 1.7
257 root 1.4 if (disease->env)
258     {
259 root 1.7 x = disease->env->x;
260     y = disease->env->y;
261 root 1.4 map = disease->env->map;
262     }
263     else
264     {
265 root 1.7 x = disease->x;
266     y = disease->y;
267 root 1.4 map = disease->map;
268     }
269    
270 root 1.7 if (!map)
271 root 1.4 return 0;
272 root 1.7
273     for (int i = x - range; i <= x + range; i++)
274     for (int j = y - range; j <= y + range; j++)
275     {
276     sint16 i2, j2;
277 root 1.39 int mflags = get_map_flags (map, &map2, i, j, &i2, &j2);
278 root 1.7
279     if (!(mflags & P_OUT_OF_MAP) && (mflags & P_IS_ALIVE))
280 root 1.12 for (tmp = GET_MAP_OB (map2, i2, j2); tmp; tmp = tmp->above)
281 root 1.7 infect_object (tmp, disease, 0);
282     }
283    
284 root 1.4 return 1;
285 elmex 1.1 }
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    
315     /* There used to (IMO) be a flaw in the below - it used to be the case
316     * that if level check was done for both immunity and disease. This could
317     * result in a person with multiple afflictions of the same disease
318     * (eg, level 1 cold, level 2 cold, level 3 cold, etc), as long as
319     * they were cast in that same order. Instead, change it so that
320     * if you diseased, you can't get diseased more.
321     */
322    
323 root 1.35 for (tmp = victim->head_ ()->inv; tmp; tmp = tmp->below)
324     if (tmp->type == SIGN && tmp->name == disease->name && tmp->level >= disease->level)
325     return 0; /* Immune! */
326     else if (tmp->type == DISEASE && tmp->name == disease->name)
327     return 0; /* already diseased */
328 root 1.4
329     /* If we've gotten this far, go ahead and infect the victim. */
330 root 1.35
331 root 1.10 new_disease = disease->clone ();
332 root 1.35
333 root 1.4 new_disease->stats.food = disease->stats.maxgrace;
334 root 1.35 new_disease->value = disease->stats.maxhp;
335     new_disease->stats.wc -= disease->last_grace; /* self-limiting factor */
336 root 1.4
337 root 1.35 /* This appears to be a horrible case of overloading 'NO_PASS'
338     * for meaning in the diseases.
339 root 1.4 */
340 root 1.35 new_disease->move_block = 0;
341    
342     // insert before setting the owner
343     victim->head_ ()->insert (new_disease);
344 root 1.4
345 root 1.11 if (disease->owner)
346 root 1.35 new_disease->set_owner (disease->owner);
347     else if (object *pl = disease->in_player ())
348     /* for diseases which are passed by hitting, set owner and skill */
349     new_disease->set_owner (pl);
350 elmex 1.1
351 root 1.4 if (new_disease->owner && new_disease->owner->type == PLAYER)
352     {
353 root 1.35 const char *buf;
354 root 1.4
355     /* if the disease has a title, it has a special infection message
356     * This messages is printed in the form MESSAGE victim
357     */
358     if (new_disease->title)
359 root 1.35 buf = format ("%s %s!!", &disease->title, &victim->name);
360 root 1.4 else
361 root 1.35 buf = format ("You infect %s with your disease, %s!", &victim->name, &new_disease->name);
362 root 1.4
363     if (victim->type == PLAYER)
364     new_draw_info (NDI_UNIQUE | NDI_RED, 0, new_disease->owner, buf);
365     else
366     new_draw_info (0, 4, new_disease->owner, buf);
367 elmex 1.1 }
368 root 1.30
369 root 1.4 if (victim->type == PLAYER)
370     new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, "You suddenly feel ill.");
371 elmex 1.1
372 root 1.4 return 1;
373 elmex 1.1 }
374    
375     /* this function monitors the symptoms caused by the disease (if any),
376     causes symptoms, and modifies existing symptoms in the case of
377     existing diseases. */
378 root 1.4 int
379     do_symptoms (object *disease)
380     {
381     object *symptom;
382     object *victim;
383     object *tmp;
384    
385     victim = disease->env;
386    
387 root 1.30 if (!victim)
388     return 0; /* no-one to inflict symptoms on */
389    
390 root 1.4 /* This is a quick hack - for whatever reason, disease->env will point
391     * back to disease, causing endless loops. Why this happens really needs
392     * to be found, but this should at least prevent the infinite loops.
393     */
394 root 1.30 //TODO: should no longer be the case, monitor, and remove
395     if (victim == disease)
396     {
397     LOG (llevError | logBacktrace, "%s: disease->env points to itself", disease->debug_desc ());
398     return 0;
399     }
400 root 1.4
401     symptom = find_symptom (disease);
402 root 1.30 if (!symptom)
403 root 1.4 {
404     /* no symptom? need to generate one! */
405    
406     /* first check and see if the carrier of the disease is immune. If so, no symptoms! */
407     if (!is_susceptible_to_disease (victim, disease))
408     return 0;
409    
410     /* check for an actual immunity */
411     /* do an immunity check */
412 root 1.35 for (tmp = victim->head_ ()->inv; tmp; tmp = tmp->below)
413 root 1.30 if (tmp->type == SIGN) /* possibly an immunity, or diseased */
414     if (tmp->name == disease->name && tmp->level >= disease->level)
415 root 1.35 return 0; /* Immune! */
416 root 1.2
417 root 1.35 object *new_symptom = get_archetype ("symptom");
418 root 1.4
419     /* Something special done with dam. We want diseases to be more
420     * random in what they'll kill, so we'll make the damage they
421     * do random, note, this has a weird effect with progressive diseases.
422     */
423 root 1.35 if (disease->stats.dam)
424 root 1.4 {
425     int dam = disease->stats.dam;
426    
427     /* reduce the damage, on average, 50%, and making things random. */
428    
429 root 1.18 dam = random_roll (1, abs (dam), victim, PREFER_LOW);
430 root 1.4 if (disease->stats.dam < 0)
431     dam = -dam;
432 root 1.30
433 root 1.4 new_symptom->stats.dam = dam;
434 root 1.2 }
435 elmex 1.1
436 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
437 root 1.29 new_symptom->stats.food = new_symptom->stats.maxgrace;
438 root 1.4
439     new_symptom->name = new_symptom->name_pl = disease->name;
440    
441     new_symptom->level = disease->level;
442     new_symptom->speed = disease->speed;
443     new_symptom->value = 0;
444 root 1.22
445     for (int i = 0; i < NUM_STATS; ++i)
446     new_symptom->stats.stat (i) = disease->stats.stat (i);
447    
448 root 1.29 new_symptom->stats.sp = disease->stats.sp;
449     new_symptom->stats.food = disease->last_eat;
450 root 1.4 new_symptom->stats.maxsp = disease->stats.maxsp;
451 root 1.29 new_symptom->last_sp = disease->last_sp;
452     new_symptom->stats.exp = 0;
453     new_symptom->stats.hp = disease->stats.hp;
454     new_symptom->msg = disease->msg;
455     new_symptom->attacktype = disease->attacktype;
456     new_symptom->other_arch = disease->other_arch;
457 root 1.35 new_symptom->skill = disease->skill;
458    
459     new_symptom->move_block = 0;
460    
461     victim->head_ ()->insert (new_symptom);
462 root 1.4
463 root 1.36 // set owner last, as insert clears owner
464 root 1.11 new_symptom->set_owner (disease->owner);
465 root 1.4
466     return 1;
467     }
468    
469 root 1.23 /* now deal with progressing diseases: we increase the debility
470 root 1.4 * caused by the symptoms.
471     */
472 root 1.29 if (disease->stats.ac)
473 root 1.4 {
474 root 1.29 symptom->value = clamp (symptom->value + disease->stats.ac, 0, 100*100);
475 root 1.4
476 root 1.23 float scale = 1.f + symptom->value / 100.f;
477 root 1.22
478 root 1.4 /* now rescale all the debilities */
479 root 1.22 for (int i = 0; i < NUM_STATS; ++i)
480 root 1.31 symptom->stats.stat (i) = clamp (int (scale * disease->stats.stat (i)), -128, 127);
481 root 1.22
482 root 1.29 symptom->stats.dam = clamp (scale * disease->stats.dam , -1024, 1024);
483     symptom->stats.food = clamp (scale * disease->last_eat , -1024, 1024);
484     symptom->stats.maxsp = clamp (scale * disease->stats.maxsp, -1024, 1024);
485     symptom->stats.sp = clamp (scale * disease->stats.sp , -1024, 1024);
486     symptom->stats.hp = clamp (scale * disease->stats.hp , -1024, 1024);
487 root 1.22 symptom->stats.exp = 0;
488 root 1.33 symptom->last_sp = disease->last_sp ? clamp (disease->last_sp / scale, 1, 1024) : 0;
489 root 1.29 symptom->msg = disease->msg;
490     symptom->attacktype = disease->attacktype;
491     symptom->other_arch = disease->other_arch;
492 elmex 1.1 }
493 root 1.23
494 root 1.4 SET_FLAG (symptom, FLAG_APPLIED);
495 root 1.13 victim->update_stats ();
496 root 1.23
497 root 1.4 return 1;
498 elmex 1.1 }
499    
500     /* grants immunity to plagues we've seen before. */
501 root 1.4 int
502     grant_immunity (object *disease)
503     {
504     object *immunity;
505 elmex 1.1 object *walk;
506 root 1.4
507 elmex 1.1 /* Don't give immunity to this disease if last_heal is set. */
508 root 1.4 if (disease->last_heal)
509     return 0;
510 root 1.35
511 elmex 1.1 /* first, search for an immunity of the same name */
512 root 1.4 for (walk = disease->env->inv; walk; walk = walk->below)
513 root 1.35 if (walk->type == 98 && disease->name == walk->name)
514     {
515     walk->level = disease->level;
516     return 1; /* just update the existing immunity. */
517     }
518    
519 root 1.4 immunity = get_archetype ("immunity");
520 root 1.35
521     immunity->name = disease->name;
522     immunity->level = disease->level;
523 elmex 1.1 immunity->move_block = 0;
524 root 1.35
525 root 1.4 insert_ob_in_ob (immunity, disease->env);
526 root 1.35
527 elmex 1.1 return 1;
528     }
529    
530     /* make the symptom do the nasty things it does */
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 root 1.36 if (!victim || !victim->map)
539 root 1.4 { /* outside a monster/player, die immediately */
540 root 1.47 symptom->destroy (true);
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 root 1.45 hit_player (victim, max (1, -victim->stats.maxhp * symptom->stats.dam / 100), symptom, symptom->attacktype, 1);
548 root 1.4
549     if (symptom->stats.maxsp > 0)
550     sp_reduce = symptom->stats.maxsp;
551     else
552 root 1.45 sp_reduce = max (1, victim->stats.maxsp * symptom->stats.maxsp / 100);
553 root 1.35
554 root 1.37 victim->stats.sp = max (0, victim->stats.sp - sp_reduce);
555 root 1.4
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.42 if (victim->map)
561     {
562     victim->play_sound (symptom->sound);
563    
564     if (symptom->other_arch)
565     for (object *tmp = victim->head_ (); tmp; tmp = tmp->more)
566     {
567     new_ob = arch_to_object (symptom->other_arch);
568     new_ob->x = tmp->x;
569     new_ob->y = tmp->y;
570     new_ob->map = victim->map;
571     insert_ob_in_map (new_ob, victim->map, victim, 0);
572     }
573     }
574 root 1.4
575     new_draw_info (NDI_UNIQUE | NDI_RED, 0, victim, symptom->msg);
576    
577     return 1;
578 elmex 1.1 }
579    
580 root 1.20 /* possibly infect due to direct physical contact
581     * i.e., AT_PHYSICAL-- called from "hit_player_attacktype" */
582 root 1.4 int
583     check_physically_infect (object *victim, object *hitter)
584     {
585 root 1.20 /* search for diseases, give every disease a chance to infect */
586     for (object *disease = hitter->inv; disease; disease = disease->below)
587     if (disease->type == DISEASE)
588     infect_object (victim, disease, 0);
589 root 1.4
590 elmex 1.1 return 1;
591     }
592    
593 root 1.20 // find a disease in someone
594 root 1.4 object *
595     find_disease (object *victim)
596     {
597 root 1.20 for (object *disease = victim->inv; disease; disease = disease->below)
598     if (disease->type == DISEASE)
599     return disease;
600 root 1.4
601 root 1.20 return 0;
602 elmex 1.1 }
603 root 1.4
604 elmex 1.1 /* do the cure disease stuff, from the spell "cure disease" */
605 root 1.4 int
606 root 1.41 cure_disease (object *sufferer, object *caster, object *spell)
607 root 1.4 {
608     object *disease, *next;
609     int cure = 0;
610    
611 root 1.41 int casting_level = caster ? caster->level : 1000; /* if null caster, CURE all. */
612 root 1.4
613     for (disease = sufferer->inv; disease; disease = next)
614     {
615     next = disease->below;
616    
617     if (disease->type == DISEASE)
618     { /* attempt to cure this disease */
619 root 1.21 /* If caster level is higher than disease level, cure chance
620 root 1.4 * is automatic. If lower, then the chance is basically
621     * 1 in level_diff - if there is a 5 level difference, chance
622     * is 1 in 5.
623     */
624     if ((casting_level >= disease->level) || (!(random_roll (0, (disease->level - casting_level - 1), caster, PREFER_LOW))))
625     {
626     remove_symptoms (disease);
627     cure = 1;
628 root 1.9
629 root 1.41 if (caster && spell)
630     change_exp (caster, disease->stats.exp, spell->skill, SK_EXP_SKILL_ONLY);
631 root 1.9
632 root 1.47 disease->destroy (true);
633 root 1.2 }
634     }
635 elmex 1.1 }
636 root 1.21
637 root 1.4 if (cure)
638     {
639     /* Only draw these messages once */
640     if (caster)
641     new_draw_info_format (NDI_UNIQUE, 0, caster, "You cure a disease!");
642 root 1.21
643 root 1.4 new_draw_info (NDI_UNIQUE, 0, sufferer, "You no longer feel diseased.");
644 elmex 1.1 }
645 root 1.21
646 elmex 1.1 return 1;
647     }
648    
649     /* reduces disease progression: reduce_symptoms
650     * return true if we actually reduce a disease.
651     */
652 root 1.4 int
653     reduce_symptoms (object *sufferer, int reduction)
654     {
655     object *walk;
656     int success = 0;
657    
658     for (walk = sufferer->inv; walk; walk = walk->below)
659     {
660     if (walk->type == SYMPTOM)
661     {
662     if (walk->value > 0)
663     {
664     success = 1;
665 root 1.29 walk->value = max (0, walk->value - 2 * reduction);
666 root 1.4 /* give the disease time to modify this symptom,
667     * and reduce its severity. */
668     walk->speed_left = 0;
669 root 1.2 }
670 root 1.4 }
671 elmex 1.1 }
672 root 1.29
673 root 1.4 if (success)
674     new_draw_info (NDI_UNIQUE, 0, sufferer, "Your illness seems less severe.");
675 root 1.29
676 root 1.4 return success;
677 elmex 1.1 }