Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_disease_c = 00003 * "$Id: disease.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 /* 00006 CrossFire, A Multiplayer game for X-windows 00007 00008 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00009 Copyright (C) 1992 Frank Tore Johansen 00010 00011 This program is free software; you can redistribute it and/or modify 00012 it under the terms of the GNU General Public License as published by 00013 the Free Software Foundation; either version 2 of the License, or 00014 (at your option) any later version. 00015 00016 This program is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 GNU General Public License for more details. 00020 00021 You should have received a copy of the GNU General Public License 00022 along with this program; if not, write to the Free Software 00023 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00024 00025 The authors can be reached via e-mail to crossfire-devel@real-time.com 00026 */ 00027 00034 /* 00035 * For DISEASES: 00036 * Stat Property Definition 00037 * 00038 * attacktype Attack effects Attacktype of the disease. usu. AT_GODPOWER. 00039 * other_arch Creation object created and dropped when symptom moved. 00040 * title Message When the "disease" "infects" something, it will 00041 * print "title victim!!!" to the player who owns 00042 * the "disease". 00043 * wc+ Infectiousness How well the plague spreads person-to-person 00044 * magic+ Range range of infection 00045 * Stats* Disability What stats are reduced by the disease (str con...) 00046 * maxhp+ Persistence How long the disease can last OUTSIDE the host. 00047 * * value TimeLeft Counter for persistence 00048 * dam^ Damage How much damage it does (%?). 00049 * maxgrace+ Duration How long before the disease is naturally cured. 00050 * food DurCount Counter for Duration 00051 * 00052 * speed Speed How often the disease moves. 00053 * last_sp^ Lethargy Percentage of max speed--10 = 10% speed. 00054 * 00055 * maxsp^ Mana deplete Saps mana. 00056 * ac^ Progressiveness How the diseases increases in severity. 00057 * last_eat*^ Deplete food saps food if negative 00058 * last_heal GrantImmunity If nonzero, disease does NOT grant immunity 00059 * when it runs out 00060 * 00061 * exp experience experience awarded when plague cured 00062 * hp*^ ReduceRegen reduces regeneration of disease-bearer 00063 * sp*^ ReduceSpRegen reduces spellpoint regeneration 00064 * 00065 * name Name Name of the plague 00066 * msg message What the plague says when it strikes. 00067 * race those affected species/race the plague strikes (* = everything) 00068 * level Plague Level General description of the plague's deadliness 00069 * armour Attenuation reduction in wc per generation of disease. 00070 * This builds in a self-limiting factor. 00071 * 00072 * 00073 * Explanations: 00074 * * means this # should be negative to cause adverse effect. 00075 * + means that this effect is modulated in spells by ldur 00076 * ^ means that this effect is modulated in spells by ldam 00077 * 00078 * attacktype is the attacktype used by the disease to smite "dam" damage with. 00079 * 00080 * wc/127 is the chance of someone in range catching it. 00081 * 00082 * magic is the range at which infection may occur. If negative, the range is 00083 * NOT level dependent. 00084 * 00085 * Stats are stat modifications. These should typically be negative. 00086 * 00087 * maxhp is how long the disease will persist if the host dies and "drops" it, 00088 * in "disease moves", i.e., moves of the disease. If negative, permanent. 00089 * 00090 * value is the counter for maxhp, it starts at maxhp and drops... 00091 * 00092 * dam if positive, it is straight damage. if negative, a %-age. 00093 * 00094 * maxgrace how long in "disease moves" the disease lasts in the host, if negative, 00095 * permanent until cured. 00096 * 00097 * food if negative, disease is permanent. otherwise, decreases at <speed>, 00098 * disease goes away at food=0, set to "maxgrace" on infection. 00099 * 00100 * speed is the speed of the disease, how fast "disease moves" occur. 00101 * 00102 * last_sp is the lethargy imposed on the player by the disease. A lethargy 00103 * of "1" reduces the players speed to 1% of its normal value. 00104 * 00105 * maxsp how much mana is sapped per "disease move". if negative, a %-age is 00106 * taken. 00107 * 00108 * ac every "disease move" the severity of the symptoms are increased by 00109 * ac/100. (severity = 1 + (accumlated_progression)/100) 00110 * 00111 * last_eat increases food usage if negative. 00112 * 00113 * 00114 * 00115 * For SYMPTOMS: 00116 * 00117 * Stats modify stats 00118 * hp modify regen 00119 * value progression counter (multiplier = value/100) 00120 * food modify food use (from last_eat in DISEASE) 00121 * maxsp suck mana ( as noted for DISEASE) 00122 * last_sp Lethargy 00123 * msg What to say 00124 * speed speed of movement, from DISEASE 00125 */ 00126 00127 #include <global.h> 00128 #include <object.h> 00129 #include <living.h> 00130 #ifndef __CEXTRACT__ 00131 #include <sproto.h> 00132 #endif 00133 #include <spells.h> 00134 #include <sounds.h> 00135 #include <skills.h> 00136 #include <assert.h> 00137 00138 static void remove_symptoms(object *disease); 00139 static object *find_symptom(object *disease); 00140 static void check_infection(object *disease); 00141 static void do_symptoms(object *disease); 00142 static void grant_immunity(object *disease); 00143 00144 00145 00146 /* IMPLEMENTATION NOTES 00147 00148 Diseases may be contageous. They are objects which exist in a player's 00149 inventory. They themselves do nothing, except modify Symptoms, or 00150 spread to other live objects. Symptoms are what actually damage the player: 00151 these are their own object. */ 00152 00165 static int is_susceptible_to_disease(object *victim, object *disease) { 00166 /* Non living and DMs are immune. */ 00167 if (!QUERY_FLAG(victim, FLAG_ALIVE) || QUERY_FLAG(victim, FLAG_WIZ)) 00168 return 0; 00169 00170 if (strstr(disease->race, "*") && !QUERY_FLAG(victim, FLAG_UNDEAD)) 00171 return 1; 00172 00173 if ((disease->race == undead_name) && QUERY_FLAG(victim, FLAG_UNDEAD)) 00174 return 1; 00175 00176 if ((victim->race && strstr(disease->race, victim->race)) 00177 || strstr(disease->race, victim->name)) 00178 return 1; 00179 00180 return 0; 00181 } 00182 00192 int move_disease(object *disease) { 00193 /* first task is to determine if the disease is inside or outside of someone. 00194 * If outside, we decrement 'value' until we're gone. 00195 */ 00196 00197 /* DMs don't infect, and don't suffer either. */ 00198 if (disease->env && QUERY_FLAG(disease->env, FLAG_WIZ)) 00199 return 0; 00200 00201 if (disease->env == NULL) { /* we're outside of someone */ 00202 if (disease->stats.maxhp > 0) 00203 disease->value--; 00204 if (disease->value == 0) { 00205 remove_ob(disease); 00206 free_object(disease); 00207 return 1; 00208 } 00209 } else { 00210 /* if we're inside a person, have the disease run its course */ 00211 /* negative foods denote "perpetual" diseases. */ 00212 if (disease->stats.food > 0) { 00213 disease->stats.food--; 00214 if (disease->stats.food == 0) { 00215 remove_symptoms(disease); /* remove the symptoms of this disease */ 00216 grant_immunity(disease); 00217 remove_ob(disease); 00218 free_object(disease); 00219 return 1; 00220 } 00221 } 00222 } 00223 /* check to see if we infect others */ 00224 check_infection(disease); 00225 00226 /* impose or modify the symptoms of the disease */ 00227 if (disease->env && is_susceptible_to_disease(disease->env, disease)) 00228 do_symptoms(disease); 00229 00230 return 0; 00231 } 00232 00244 static void remove_symptoms(object *disease) { 00245 object *symptom, *victim = NULL; 00246 00247 assert(disease != NULL); 00248 00249 while ((symptom = find_symptom(disease)) != NULL) { 00250 if (!victim) 00251 victim = symptom->env; 00252 remove_ob(symptom); 00253 free_object(symptom); 00254 } 00255 if (victim) 00256 fix_object(victim); 00257 } 00258 00267 static object *find_symptom(object *disease) { 00268 object *walk; 00269 00270 assert(disease->env != NULL); 00271 00272 /* check the inventory for symptoms */ 00273 for (walk = disease->env->inv; walk; walk = walk->below) 00274 if (!strcmp(walk->name, disease->name) && walk->type == SYMPTOM) 00275 return walk; 00276 return NULL; 00277 } 00278 00285 static void check_infection(object *disease) { 00286 int x, y, range, mflags; 00287 mapstruct *map, *map2; 00288 object *tmp; 00289 sint16 i, j, i2, j2; 00290 00291 range = abs(disease->magic); 00292 if (disease->env) { 00293 x = disease->env->x; 00294 y = disease->env->y; 00295 map = disease->env->map; 00296 } else { 00297 x = disease->x; 00298 y = disease->y; 00299 map = disease->map; 00300 } 00301 00302 if (map == NULL) 00303 return; 00304 for (i = x-range; i <= x+range; i++) { 00305 for (j = y-range; j <= y+range; j++) { 00306 mflags = get_map_flags(map, &map2, i, j, &i2, &j2); 00307 if (!(mflags&P_OUT_OF_MAP) && (mflags&P_IS_ALIVE)) { 00308 for (tmp = GET_MAP_OB(map2, i2, j2); tmp; tmp = tmp->above) { 00309 infect_object(tmp, disease, 0); 00310 } 00311 } 00312 } 00313 } 00314 return; 00315 } 00316 00336 int infect_object(object *victim, object *disease, int force) { 00337 object *tmp; 00338 object *new_disease; 00339 00340 /* don't infect inanimate objects */ 00341 if (!QUERY_FLAG(victim, FLAG_MONSTER) && !(victim->type == PLAYER)) 00342 return 0; 00343 00344 /* check and see if victim can catch disease: diseases 00345 * are specific 00346 */ 00347 if (!is_susceptible_to_disease(victim, disease)) 00348 return 0; 00349 00350 /* If disease is on battleground, only infect other victims on battleground. 00351 Not checking results in spectators being infected, which could lead to PK. */ 00352 if ((disease->map && op_on_battleground(disease, NULL, NULL, NULL)) 00353 || (disease->env && op_on_battleground(disease->env, NULL, NULL, NULL))) 00354 if (!op_on_battleground(victim, NULL, NULL, NULL)) 00355 return 0; 00356 00357 /* roll the dice on infection before doing the inventory check! */ 00358 if (!force && (random_roll(0, 126, victim, PREFER_HIGH) >= disease->stats.wc)) 00359 return 0; 00360 00361 /* do an immunity check */ 00362 if (victim->head) 00363 tmp = victim->head->inv; 00364 else 00365 tmp = victim->inv; 00366 00367 /* There used to (IMO) be a flaw in the below - it used to be the case 00368 * that if level check was done for both immunity and disease. This could 00369 * result in a person with multiple afflictions of the same disease 00370 * (eg, level 1 cold, level 2 cold, level 3 cold, etc), as long as 00371 * they were cast in that same order. Instead, change it so that 00372 * if you diseased, you can't get diseased more. 00373 */ 00374 00375 for (/* tmp initialized in if, above */; tmp; tmp = tmp->below) { 00376 if (tmp->type == SIGN && !strcmp(tmp->name, disease->name) && tmp->level >= disease->level) 00377 return 0; /*Immune! */ 00378 else if (tmp->type == DISEASE && !strcmp(tmp->name, disease->name)) 00379 return 0; /* already diseased */ 00380 } 00381 00382 /* If we've gotten this far, go ahead and infect the victim. */ 00383 new_disease = get_object(); 00384 copy_object(disease, new_disease); 00385 new_disease->stats.food = disease->stats.maxgrace; 00386 new_disease->value = disease->stats.maxhp; 00387 new_disease->stats.wc -= disease->last_grace; /* self-limiting factor */ 00388 00389 /* Unfortunately, set_owner does the wrong thing to the skills pointers 00390 * resulting in exp going into the owners *current *chosen skill. 00391 */ 00392 00393 if (get_owner(disease)) { 00394 set_owner(new_disease, disease->owner); 00395 00396 /* Only need to update skill if different */ 00397 if (new_disease->skill != disease->skill) { 00398 if (new_disease->skill) 00399 free_string(new_disease->skill); 00400 if (disease->skill) 00401 new_disease->skill = add_refcount(disease->skill); 00402 } 00403 } else { /* for diseases which are passed by hitting, set owner and praying skill*/ 00404 if (disease->env && disease->env->type == PLAYER) { 00405 object *player = disease->env; 00406 00407 set_owner(new_disease, player); 00408 /* the skill pointer for these diseases should already be set up - 00409 * hardcoding in 'praying' is not the right approach. 00410 */ 00411 } 00412 } 00413 00414 insert_ob_in_ob(new_disease, victim); 00415 /* This appears to be a horrible case of overloading 'NO_PASS' 00416 * for meaning in the diseases. 00417 */ 00418 new_disease->move_block = 0; 00419 if (new_disease->owner && new_disease->owner->type == PLAYER) { 00420 char buf[128]; 00421 00422 /* if the disease has a title, it has a special infection message 00423 * This messages is printed in the form MESSAGE victim 00424 */ 00425 if (new_disease->title) 00426 snprintf(buf, sizeof(buf), "%s %s!!", disease->title, victim->name); 00427 else 00428 snprintf(buf, sizeof(buf), "You infect %s with your disease, %s!", victim->name, new_disease->name); 00429 00430 if (victim->type == PLAYER) 00431 draw_ext_info(NDI_UNIQUE|NDI_RED, 0, new_disease->owner, MSG_TYPE_ATTACK, MSG_TYPE_ATTACK_DID_HIT, 00432 buf, buf); 00433 else 00434 draw_ext_info(0, 4, new_disease->owner, MSG_TYPE_ATTACK, MSG_TYPE_ATTACK_DID_HIT, 00435 buf, buf); 00436 } 00437 if (victim->type == PLAYER) 00438 draw_ext_info(NDI_UNIQUE|NDI_RED, 0, victim, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START, 00439 "You suddenly feel ill.", NULL); 00440 00441 return 1; 00442 } 00443 00452 static void do_symptoms(object *disease) { 00453 object *symptom; 00454 object *victim; 00455 object *tmp; 00456 victim = disease->env; 00457 00458 /* This is a quick hack - for whatever reason, disease->env will point 00459 * back to disease, causing endless loops. Why this happens really needs 00460 * to be found, but this should at least prevent the infinite loops. 00461 */ 00462 00463 if (victim == NULL || victim == disease) 00464 return;/* no-one to inflict symptoms on */ 00465 00466 /* DMs don't suffer from diseases. */ 00467 if (QUERY_FLAG(victim, FLAG_WIZ)) 00468 return; 00469 00470 symptom = find_symptom(disease); 00471 if (symptom == NULL) { 00472 /* no symptom? need to generate one! */ 00473 object *new_symptom; 00474 00475 /* first check and see if the carrier of the disease is immune. If so, no symptoms! */ 00476 if (!is_susceptible_to_disease(victim, disease)) 00477 return; 00478 00479 /* check for an actual immunity */ 00480 /* do an immunity check */ 00481 if (victim->head) 00482 tmp = victim->head->inv; 00483 else 00484 tmp = victim->inv; 00485 00486 for (/* tmp initialized in if, above */; tmp; tmp = tmp->below) { 00487 if (tmp->type == SIGN) /* possibly an immunity, or diseased*/ 00488 if (!strcmp(tmp->name, disease->name) && tmp->level >= disease->level) 00489 return; /*Immune! */ 00490 } 00491 00492 new_symptom = create_archetype(ARCH_SYMPTOM); 00493 00494 /* Something special done with dam. We want diseases to be more 00495 * random in what they'll kill, so we'll make the damage they 00496 * do random, note, this has a weird effect with progressive diseases. 00497 */ 00498 if (disease->stats.dam != 0) { 00499 int dam = disease->stats.dam; 00500 00501 /* reduce the damage, on average, 50%, and making things random. */ 00502 00503 dam = random_roll(1, FABS(dam), victim, PREFER_LOW); 00504 if (disease->stats.dam < 0) 00505 dam = -dam; 00506 new_symptom->stats.dam = dam; 00507 } 00508 00509 new_symptom->stats.maxsp = disease->stats.maxsp; 00510 new_symptom->stats.food = new_symptom->stats.maxgrace; 00511 00512 FREE_AND_COPY(new_symptom->name, disease->name); 00513 FREE_AND_COPY(new_symptom->name_pl, disease->name); 00514 new_symptom->level = disease->level; 00515 new_symptom->speed = disease->speed; 00516 new_symptom->value = 0; 00517 new_symptom->stats.Str = disease->stats.Str; 00518 new_symptom->stats.Dex = disease->stats.Dex; 00519 new_symptom->stats.Con = disease->stats.Con; 00520 new_symptom->stats.Wis = disease->stats.Wis; 00521 new_symptom->stats.Int = disease->stats.Int; 00522 new_symptom->stats.Pow = disease->stats.Pow; 00523 new_symptom->stats.Cha = disease->stats.Cha; 00524 new_symptom->stats.sp = disease->stats.sp; 00525 new_symptom->stats.food = disease->last_eat; 00526 new_symptom->stats.maxsp = disease->stats.maxsp; 00527 new_symptom->last_sp = disease->last_sp; 00528 new_symptom->stats.exp = 0; 00529 new_symptom->stats.hp = disease->stats.hp; 00530 new_symptom->msg = add_string(disease->msg); 00531 new_symptom->attacktype = disease->attacktype; 00532 new_symptom->other_arch = disease->other_arch; 00533 00534 set_owner(new_symptom, disease->owner); 00535 if (new_symptom->skill != disease->skill) { 00536 if (new_symptom->skill) 00537 free_string(new_symptom->skill); 00538 if (disease->skill) 00539 new_symptom->skill = add_refcount(disease->skill); 00540 } 00541 new_symptom->move_block = 0; 00542 insert_ob_in_ob(new_symptom, victim); 00543 return; 00544 } 00545 00546 /* now deal with progressing diseases: we increase the debility 00547 * caused by the symptoms. 00548 */ 00549 00550 if (disease->stats.ac != 0) { 00551 float scale; 00552 00553 symptom->value += disease->stats.ac; 00554 scale = 1.0+symptom->value/100.0; 00555 /* now rescale all the debilities */ 00556 symptom->stats.Str = (int)(scale*disease->stats.Str); 00557 symptom->stats.Dex = (int)(scale*disease->stats.Dex); 00558 symptom->stats.Con = (int)(scale*disease->stats.Con); 00559 symptom->stats.Wis = (int)(scale*disease->stats.Wis); 00560 symptom->stats.Int = (int)(scale*disease->stats.Int); 00561 symptom->stats.Pow = (int)(scale*disease->stats.Pow); 00562 symptom->stats.Cha = (int)(scale*disease->stats.Cha); 00563 symptom->stats.dam = (int)(scale*disease->stats.dam); 00564 symptom->stats.sp = (int)(scale*disease->stats.sp); 00565 symptom->stats.food = (int)(scale*disease->last_eat); 00566 symptom->stats.maxsp = (int)(scale*disease->stats.maxsp); 00567 symptom->last_sp = (int)(scale*disease->last_sp); 00568 symptom->stats.exp = 0; 00569 symptom->stats.hp = (int)(scale*disease->stats.hp); 00570 symptom->msg = add_string(disease->msg); 00571 symptom->attacktype = disease->attacktype; 00572 symptom->other_arch = disease->other_arch; 00573 } 00574 SET_FLAG(symptom, FLAG_APPLIED); 00575 fix_object(victim); 00576 } 00577 00584 static void grant_immunity(object *disease) { 00585 object *immunity; 00586 object *walk; 00587 00588 /* Don't give immunity to this disease if last_heal is set. */ 00589 if (disease->last_heal) 00590 return; 00591 00592 assert(disease->env != NULL); 00593 00594 /* first, search for an immunity of the same name */ 00595 for (walk = disease->env->inv; walk; walk = walk->below) { 00596 if (walk->type == SIGN && !strcmp(disease->name, walk->name)) { 00597 walk->level = disease->level; 00598 return; /* just update the existing immunity. */ 00599 } 00600 } 00601 immunity = create_archetype("immunity"); 00602 immunity->name = add_string(disease->name); 00603 immunity->level = disease->level; 00604 immunity->move_block = 0; 00605 insert_ob_in_ob(immunity, disease->env); 00606 return; 00607 } 00608 00615 void move_symptom(object *symptom) { 00616 object *victim = symptom->env; 00617 object *new_ob; 00618 int sp_reduce; 00619 tag_t tag = symptom->count; 00620 00621 if (victim == NULL || victim->map == NULL) { /* outside a monster/player, die immediately */ 00622 remove_ob(symptom); 00623 free_object(symptom); 00624 return; 00625 } 00626 00627 if (symptom->stats.dam > 0) 00628 hit_player(victim, symptom->stats.dam, symptom, symptom->attacktype, 1); 00629 else 00630 hit_player(victim, MAX(1, -victim->stats.maxhp*symptom->stats.dam/100.0), symptom, symptom->attacktype, 1); 00631 00632 /* In most cases, if the victim has been freed, the logic that 00633 * does that will also free the symptom, so check for that. 00634 */ 00635 if (QUERY_FLAG(victim, FLAG_FREED)) { 00636 if (!was_destroyed(symptom, tag)) { 00637 remove_ob(symptom); 00638 free_object(symptom); 00639 } 00640 return; 00641 } 00642 00643 if (symptom->stats.maxsp > 0) 00644 sp_reduce = symptom->stats.maxsp; 00645 else 00646 sp_reduce = MAX(1, victim->stats.maxsp*symptom->stats.maxsp/100.0); 00647 victim->stats.sp = MAX(0, victim->stats.sp-sp_reduce); 00648 00649 /* create the symptom "other arch" object and drop it here 00650 * under every part of the monster 00651 * The victim may well have died. 00652 */ 00653 00654 if (symptom->other_arch) { 00655 object *tmp; 00656 00657 tmp = victim; 00658 if (tmp->head != NULL) 00659 tmp = tmp->head; 00660 for (/*tmp initialized above */; tmp != NULL; tmp = tmp->more) { 00661 char name[MAX_BUF]; 00662 00663 new_ob = arch_to_object(symptom->other_arch); 00664 snprintf(name, sizeof(name), "%s's %s", victim->name, new_ob->name); 00665 FREE_AND_COPY(new_ob->name, name); 00666 if (new_ob->name_pl != NULL) { 00667 snprintf(name, sizeof(name), "%s's %s", victim->name, new_ob->name_pl); 00668 FREE_AND_COPY(new_ob->name_pl, name); 00669 } 00670 new_ob->x = tmp->x; 00671 new_ob->y = tmp->y; 00672 new_ob->map = victim->map; 00673 insert_ob_in_map(new_ob, victim->map, victim, 0); 00674 } 00675 } 00676 if (!symptom->msg) { 00677 LOG(llevError, "BUG: move_symptom(): symptom %d (%s) without message!\n", symptom->count, symptom->name); 00678 return; 00679 } 00680 draw_ext_info(NDI_UNIQUE|NDI_RED, 0, victim, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START, 00681 symptom->msg, symptom->msg); 00682 return; 00683 } 00684 00694 void check_physically_infect(object *victim, object *hitter) { 00695 object *walk; 00696 00697 /* search for diseases, give every disease a chance to infect */ 00698 for (walk = hitter->inv; walk != NULL; walk = walk->below) 00699 if (walk->type == DISEASE) 00700 infect_object(victim, walk, 0); 00701 } 00702 00715 int cure_disease(object *sufferer, object *caster) { 00716 object *disease, *next; 00717 int casting_level; 00718 int cure = 0; 00719 00720 if (caster) 00721 casting_level = caster->level; 00722 else 00723 casting_level = 1000; /* if null caster, CURE all. */ 00724 00725 for (disease = sufferer->inv; disease; disease = next) { 00726 next = disease->below; 00727 00728 if (disease->type == DISEASE && !QUERY_FLAG(disease, FLAG_STARTEQUIP)) { 00729 /* attempt to cure this disease. God-given diseases are given by the god, so don't remove them */ 00730 /* If caster lvel is higher than disease level, cure chance 00731 * is automatic. If lower, then the chance is basically 00732 * 1 in level_diff - if there is a 5 level difference, chance 00733 * is 1 in 5. 00734 */ 00735 if ((casting_level >= disease->level) 00736 || (!(random_roll(0, (disease->level-casting_level-1), caster, PREFER_LOW)))) { 00737 remove_symptoms(disease); 00738 remove_ob(disease); 00739 cure = 1; 00740 if (caster) 00741 change_exp(caster, disease->stats.exp, caster->chosen_skill ? caster->chosen_skill->skill : NULL, 0); 00742 free_object(disease); 00743 } 00744 } 00745 } 00746 if (cure) { 00747 /* Only draw these messages once */ 00748 if (caster) 00749 draw_ext_info_format(NDI_UNIQUE, 0, caster, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL, 00750 "You cure a disease!", NULL); 00751 00752 draw_ext_info(NDI_UNIQUE, 0, sufferer, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END, 00753 "You no longer feel diseased.", NULL); 00754 } 00755 return cure; 00756 }