Version 3.3.1 of NetHack has a number of minor inconsistencies with the handling of lava pools as compared to water pools: - Objects dropped into a lava pool (eg., when polymorphed into a salamander) take no damage. - Objects kicked across lava pools skim the surface while they fall into pools of water. - If a monster revives in a lava pool (eg., trolls) they walk out unhurt, but can drown in water. - Monsters who enter lava pools (eg., a pet by displacement) take no damage. This patch makes the following changes: - Change name of minwater() to minliquid() to reflect its new generality. - minliquid() now deals with lava as well as water. - New function fire_damage() analagous to water_damage(). - flooreffects() now deals with lava as well as water. - Scrolls, spellbooks, potions and flammable items can be damaged by lava: - For ease of implementation, exploding potions don't do damage (to be consistent, they probably should). - Containers (except ice boxes) have a chance of being destroyed and their contents spilt (which then take damage themselves). - The Candelabrum of Invocation, candles, lamps, lanterns and potions of oil catch light when damaged by lava (handled by a new function, catch_lit): Objects with no fuel and wished-for magic lamps can't be lit but the Candelabrum of Invocation can, even when cursed. - Kicked objects fall into lava pools. - Lava likers can protect their stuff in lava pools (as swimmers in water pools). Fire resistant monsters can only protect themselves (and take some damage anyway). Non-fire resistant monsters die instantly. diff -Naurd ../nethack-3.3.1/include/extern.h ./include/extern.h --- ../nethack-3.3.1/include/extern.h Wed Aug 9 16:46:17 2000 +++ ./include/extern.h Thu Oct 5 20:42:11 2000 @@ -43,6 +43,7 @@ E boolean FDECL(um_dist, (XCHAR_P,XCHAR_P,XCHAR_P)); E boolean FDECL(snuff_candle, (struct obj *)); E boolean FDECL(snuff_lit, (struct obj *)); +E boolean FDECL(catch_lit, (struct obj *)); E void FDECL(use_unicorn_horn, (struct obj *)); E boolean FDECL(tinnable, (struct obj *)); E void NDECL(reset_trapset); @@ -1030,7 +1031,7 @@ E int FDECL(undead_to_corpse, (int)); E int FDECL(pm_to_cham, (int)); -E int FDECL(minwater, (struct monst *)); +E int FDECL(minliquid, (struct monst *)); E int NDECL(movemon); E int FDECL(meatgold, (struct monst *)); E int FDECL(meatobj, (struct monst *)); @@ -1879,6 +1880,7 @@ E void NDECL(float_up); E void FDECL(fill_pit, (int,int)); E int FDECL(float_down, (long, long)); +E int FDECL(fire_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P,xchar,xchar)); E void FDECL(water_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P)); E boolean NDECL(drown); E void FDECL(drain_en, (int)); diff -Naurd ../nethack-3.3.1/src/apply.c ./src/apply.c --- ../nethack-3.3.1/src/apply.c Thu Aug 3 20:30:51 2000 +++ ./src/apply.c Wed Oct 4 17:58:05 2000 @@ -1010,6 +1010,32 @@ return FALSE; } +/* Called when potentially lightable object is affected by fire_damage(). + Return TRUE if object was lit and FALSE otherwise --ALI */ +boolean +catch_lit(obj) +struct obj *obj; +{ + xchar x, y; + + if (!obj->lamplit && (obj->otyp == CANDELABRUM_OF_INVOCATION || + obj->otyp == WAX_CANDLE || obj->otyp == TALLOW_CANDLE || + obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || + obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL)) { + if (obj->otyp == MAGIC_LAMP && obj->spe == 0) + return FALSE; + else if (obj->otyp != MAGIC_LAMP && obj->age == 0) + return FALSE; + if (!get_obj_location(obj, &x, &y, 0)) + return FALSE; + if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind) + pline("%s catches light!", Yname2(obj)); + begin_burn(obj, TRUE); + return TRUE; + } + return FALSE; +} + STATIC_OVL void use_lamp(obj) struct obj *obj; diff -Naurd ../nethack-3.3.1/src/do.c ./src/do.c --- ../nethack-3.3.1/src/do.c Mon Jul 17 01:15:55 2000 +++ ./src/do.c Thu Oct 5 20:42:36 2000 @@ -197,6 +197,8 @@ bury_objs(x, y); newsym(x,y); return TRUE; + } else if (is_lava(x, y)) { + return fire_damage(obj, FALSE, FALSE, x, y); } else if (is_pool(x, y)) { water_damage(obj, FALSE, FALSE); } diff -Naurd ../nethack-3.3.1/src/fountain.c ./src/fountain.c --- ../nethack-3.3.1/src/fountain.c Sat Aug 5 00:37:04 2000 +++ ./src/fountain.c Tue Oct 3 12:36:59 2000 @@ -126,7 +126,7 @@ water_damage(level.objects[x][y], FALSE, TRUE); if ((mtmp = m_at(x, y)) != 0) - (void) minwater(mtmp); + (void) minliquid(mtmp); else newsym(x,y); } diff -Naurd ../nethack-3.3.1/src/hack.c ./src/hack.c --- ../nethack-3.3.1/src/hack.c Sat Jul 22 01:59:06 2000 +++ ./src/hack.c Fri Oct 6 18:42:40 2000 @@ -979,7 +979,7 @@ place_monster(mtmp, u.ux0, u.uy0); /* check for displacing it into pools and traps */ - switch (minwater(mtmp) ? 2 : mintrap(mtmp)) { + switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { case 0: You("%s %s.", mtmp->mtame ? "displaced" : "frightened", y_monnam(mtmp)); diff -Naurd ../nethack-3.3.1/src/mon.c ./src/mon.c --- ../nethack-3.3.1/src/mon.c Thu Aug 3 20:30:14 2000 +++ ./src/mon.c Fri Oct 6 19:06:44 2000 @@ -306,19 +306,21 @@ } #endif /* 0 */ -/* check mtmp and water for compatibility, 0 (survived), 1 (drowned) */ +/* check mtmp and water/lava for compatibility, 0 (survived), 1 (died) */ int -minwater(mtmp) +minliquid(mtmp) register struct monst *mtmp; { - boolean inpool, infountain; + boolean inpool, inlava, infountain; inpool = is_pool(mtmp->mx,mtmp->my) && !is_flyer(mtmp->data) && !is_floater(mtmp->data); + inlava = is_lava(mtmp->mx,mtmp->my) && + !is_flyer(mtmp->data) && !is_floater(mtmp->data); infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ); #ifdef STEED - /* Flying and levitation keeps our steed out of the water */ + /* Flying and levitation keeps our steed out of the liquid */ /* (but not water-walking or swimming) */ if (mtmp == u.usteed && (Flying || Levitation)) return (0); @@ -347,7 +349,35 @@ return (0); } - if (inpool) { + if (inlava) { + /* + * Lava effects much as water effects. Lava likers are able to + * protect their stuff. Fire resistant monsters can only protect + * themselves --ALI + */ + if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) { + if (!resists_fire(mtmp)) { + if (cansee(mtmp->mx,mtmp->my)) + pline("%s burns to a crisp.", Monnam(mtmp)); + mondead(mtmp); + } + else { + if (--mtmp->mhp < 1) { + if (cansee(mtmp->mx,mtmp->my)) + pline("%s surrenders to the fire.", Monnam(mtmp)); + mondead(mtmp); + } + else if (cansee(mtmp->mx,mtmp->my)) + pline("%s burns slightly.", Monnam(mtmp)); + } + if (mtmp->mhp > 0) { + fire_damage(mtmp->minvent, FALSE, FALSE, mtmp->mx, mtmp->my); + rloc(mtmp); + return 0; + } + return (1); + } + } else if (inpool) { /* Most monsters drown in pools. flooreffects() will take care of * water damage to dead monsters' inventory, but survivors need to * be handled here. Swimmers are able to protect their stuff... @@ -477,7 +507,7 @@ if (mtmp->movement >= NORMAL_SPEED) somebody_can_move = TRUE; - if (minwater(mtmp)) continue; + if (minliquid(mtmp)) continue; if (is_hider(mtmp->data)) { /* unwatched mimics and piercers may hide again [MRS] */ diff -Naurd ../nethack-3.3.1/src/trap.c ./src/trap.c --- ../nethack-3.3.1/src/trap.c Sat Aug 5 00:43:52 2000 +++ ./src/trap.c Fri Oct 6 19:03:21 2000 @@ -2022,6 +2022,100 @@ } } +/* Return number of objects destroyed. --ALI */ +int +fire_damage(chain, force, here, x, y) +struct obj *chain; +boolean force, here; +xchar x, y; +{ + /* Scrolls, spellbooks, potions, and flammable items + may get affected by the fire */ + + int chance; + struct obj *obj, *otmp, *nobj, *nobj2; + int retval = 0; + int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */ + + for (obj = chain; obj; obj = nobj) { + nobj = here ? obj->nexthere : obj->nobj; + + if (catch_lit(obj)) + continue; + + if(Is_container(obj)) { + switch (obj->otyp) + { + case ICE_BOX: + continue; /* Immune */ + break; + case CHEST: + chance = 40; + break; + case LARGE_BOX: + chance = 30; + break; + default: + chance = 20; + break; + } + if (!force && (Luck + 5) > rn2(chance)) + continue; + /* Container is burnt up - dump contents out */ + pline("%s catches fire and burns.", Yname2(obj)); + if (Has_contents(obj)) { + pline("Its contents fall out."); + for (otmp = obj->cobj; otmp; otmp = nobj2) { + nobj2 = otmp->nobj; + obj_extract_self(otmp); + if (!flooreffects(otmp, x, y, "")) + place_object(otmp, x, y); + } + } + delobj(obj); + retval++; + } else if (!force && (Luck + 5) > rn2(20)) { + /* chance per item of sustaining damage: + * max luck (full moon): 5% + * max luck (elsewhen): 10% + * avg luck (Luck==0): 75% + * awful luck (Luck<-4): 100% + */ + continue; + } else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) { + if (obj->otyp == SCR_FIRE || +#ifdef MAIL + obj->otyp == SCR_MAIL || +#endif + obj->otyp == SPE_FIREBALL) + continue; + if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { + pline("Smoke rises from %s.", the(xname(obj))); + continue; + } + pline(obj->quan > 1 ? "%s catch fire and burn." : + "%s catches fire and burns.", Yname2(obj)); + delobj(obj); + retval++; + } else if (obj->oclass == POTION_CLASS) { + pline(obj->quan > 1 ? "%s boil and explode." : + "%s boils and explodes.", Yname2(obj)); + delobj(obj); + retval++; + } else if (is_flammable(obj) && obj->oeroded < MAX_ERODE && + !(obj->oerodeproof || (obj->blessed && !rnl(4)))) { + pline("%s burn%s%s.", Yname2(obj), obj->quan > 1 ? "": "s", + obj->oeroded+1 == MAX_ERODE ? " completely" : + obj->oeroded ? " further" : ""); + obj->oeroded++; + } + } + + if (retval && Blind) + You("smell smoke."); + return retval; +} + void water_damage(obj, force, here) register struct obj *obj; diff -Naurd ../nethack-3.3.1/src/zap.c ./src/zap.c --- ../nethack-3.3.1/src/zap.c Sat Aug 5 01:23:29 2000 +++ ./src/zap.c Fri Oct 6 19:17:43 2000 @@ -2574,7 +2574,8 @@ delay_output(); /* kicked objects fall in pools */ if((weapon == KICKED_WEAPON) && - is_pool(bhitpos.x, bhitpos.y)) + (is_pool(bhitpos.x, bhitpos.y) || + is_lava(bhitpos.x, bhitpos.y))) break; #ifdef SINKS if(IS_SINK(typ) && weapon != FLASHED_LIGHT) diff -Naurd ../nethack-3.3.1/sys/msdos/schema3.MSC ./sys/msdos/schema3.MSC --- ../nethack-3.3.1/sys/msdos/schema3.MSC Thu Aug 3 21:33:13 2000 +++ ./sys/msdos/schema3.MSC Tue Oct 3 12:38:59 2000 @@ -419,7 +419,7 @@ functions:383 _getprice _getreturn _getrumor _gettrack ;functions:384 functions:385 _doname _Doname2 -functions:386 _minwater +functions:386 _minliquid functions:387 _missmm functions:388 _missmu functions:389 _missum