From: Derek S. Ray Date: Tue, 24 Mar 2015 03:13:53 +0000 (-0400) Subject: add glob merging for obvious cases X-Git-Tag: NetHack-3.6.0_RC01~414^2~41^2~17 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5ccae41702f1414d71884bdb7718fdfd1b902859;p=nethack add glob merging for obvious cases flooreffects() covers most dropped/thrown/etc. cases, and the hooks in invent and mon handle "deathdrops" along with picking up items. still need to check putting into/removing from containers --- diff --git a/include/extern.h b/include/extern.h index 0a1dabe77..cfcd01760 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1212,6 +1212,9 @@ E void FDECL(obj_ice_effects, (int, int, BOOLEAN_P)); E long FDECL(peek_at_iced_corpse_age, (struct obj *)); E int FDECL(hornoplenty, (struct obj *,BOOLEAN_P)); E void NDECL(obj_sanity_check); +E struct obj* FDECL(obj_nexto, (struct obj*)); +E struct obj* FDECL(obj_nexto_xy, (int, int, int, int)); +E struct obj* FDECL(obj_meld, (struct obj**, struct obj**)); /* ### mkroom.c ### */ diff --git a/include/obj.h b/include/obj.h index 557ff5861..e6b7b1c0a 100644 --- a/include/obj.h +++ b/include/obj.h @@ -94,7 +94,7 @@ struct obj { Bitfield(recharged,3); /* number of times it's been recharged */ #define on_ice recharged /* corpse on ice */ Bitfield(lamplit,1); /* a light-source -- can be lit */ - Bitfield(oglobby,1); /* globby; will combine with like types on adjacent squares */ + Bitfield(globby,1); /* globby; will combine with like types on adjacent squares */ Bitfield(greased,1); /* covered with grease */ Bitfield(nomerge,1); /* set temporarily to prevent merging */ Bitfield(was_thrown,1); /* thrown by hero since last picked up */ diff --git a/src/do.c b/src/do.c index 3069a4047..620afe862 100644 --- a/src/do.c +++ b/src/do.c @@ -22,20 +22,20 @@ STATIC_DCL void NDECL(final_level); extern int n_dgns; /* number of dungeons, from dungeon.c */ static NEARDATA const char drop_types[] = - { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 }; + { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 }; /* 'd' command: drop one inventory item */ int dodrop() { - int result, i = (invent) ? 0 : (SIZE(drop_types) - 1); + int result, i = (invent) ? 0 : (SIZE(drop_types) - 1); - if (*u.ushops) sellobj_state(SELL_DELIBERATE); - result = drop(getobj(&drop_types[i], "drop")); - if (*u.ushops) sellobj_state(SELL_NORMAL); - reset_occupations(); + if (*u.ushops) sellobj_state(SELL_DELIBERATE); + result = drop(getobj(&drop_types[i], "drop")); + if (*u.ushops) sellobj_state(SELL_NORMAL); + reset_occupations(); - return result; + return result; } /* Called when a boulder is dropped, thrown, or pushed. If it ends up @@ -48,75 +48,75 @@ struct obj *otmp; register int rx, ry; boolean pushing; { - if (!otmp || otmp->otyp != BOULDER) - impossible("Not a boulder?"); - else if (!Is_waterlevel(&u.uz) && is_pool_or_lava(rx,ry)) { - boolean lava = is_lava(rx,ry), fills_up; - const char *what = waterbody_name(rx,ry); - schar ltyp = levl[rx][ry].typ; - int chance = rn2(10); /* water: 90%; lava: 10% */ - fills_up = lava ? chance == 0 : chance != 0; - - if (fills_up) { - struct trap *ttmp = t_at(rx, ry); - - if (ltyp == DRAWBRIDGE_UP) { - levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ - levl[rx][ry].drawbridgemask |= DB_FLOOR; - } else - levl[rx][ry].typ = ROOM; - - if (ttmp) (void) delfloortrap(ttmp); - bury_objs(rx, ry); - - newsym(rx,ry); - if (pushing) { - char whobuf[BUFSZ]; - - Strcpy(whobuf, "you"); - if (u.usteed) Strcpy(whobuf, y_monnam(u.usteed)); - pline("%s %s %s into the %s.", upstart(whobuf), - vtense(whobuf, "push"), the(xname(otmp)), what); - if (flags.verbose && !Blind) - pline("Now you can cross it!"); - /* no splashing in this case */ - } - } - if (!fills_up || !pushing) { /* splashing occurs */ - if (!u.uinwater) { - if (pushing ? !Blind : cansee(rx,ry)) { - There("is a large splash as %s %s the %s.", - the(xname(otmp)), fills_up? "fills":"falls into", - what); - } else if (!Deaf) - You_hear("a%s splash.", lava ? " sizzling" : ""); - wake_nearto(rx, ry, 40); - } - - if (fills_up && u.uinwater && distu(rx,ry) == 0) { - u.uinwater = 0; - docrt(); - vision_full_recalc = 1; - You("find yourself on dry land again!"); - } else if (lava && distu(rx,ry) <= 2) { - int dmg; - You("are hit by molten lava%c", - Fire_resistance ? '.' : '!'); - burn_away_slime(); - dmg = d((Fire_resistance ? 1 : 3), 6); - losehp(Maybe_Half_Phys(dmg), /* lava damage */ - "molten lava", KILLED_BY); - } else if (!fills_up && flags.verbose && - (pushing ? !Blind : cansee(rx,ry))) - pline("It sinks without a trace!"); - } - - /* boulder is now gone */ - if (pushing) delobj(otmp); - else obfree(otmp, (struct obj *)0); - return TRUE; - } - return FALSE; + if (!otmp || otmp->otyp != BOULDER) + impossible("Not a boulder?"); + else if (!Is_waterlevel(&u.uz) && is_pool_or_lava(rx,ry)) { + boolean lava = is_lava(rx,ry), fills_up; + const char *what = waterbody_name(rx,ry); + schar ltyp = levl[rx][ry].typ; + int chance = rn2(10); /* water: 90%; lava: 10% */ + fills_up = lava ? chance == 0 : chance != 0; + + if (fills_up) { + struct trap *ttmp = t_at(rx, ry); + + if (ltyp == DRAWBRIDGE_UP) { + levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ + levl[rx][ry].drawbridgemask |= DB_FLOOR; + } else + levl[rx][ry].typ = ROOM; + + if (ttmp) (void) delfloortrap(ttmp); + bury_objs(rx, ry); + + newsym(rx,ry); + if (pushing) { + char whobuf[BUFSZ]; + + Strcpy(whobuf, "you"); + if (u.usteed) Strcpy(whobuf, y_monnam(u.usteed)); + pline("%s %s %s into the %s.", upstart(whobuf), + vtense(whobuf, "push"), the(xname(otmp)), what); + if (flags.verbose && !Blind) + pline("Now you can cross it!"); + /* no splashing in this case */ + } + } + if (!fills_up || !pushing) { /* splashing occurs */ + if (!u.uinwater) { + if (pushing ? !Blind : cansee(rx,ry)) { + There("is a large splash as %s %s the %s.", + the(xname(otmp)), fills_up? "fills":"falls into", + what); + } else if (!Deaf) + You_hear("a%s splash.", lava ? " sizzling" : ""); + wake_nearto(rx, ry, 40); + } + + if (fills_up && u.uinwater && distu(rx,ry) == 0) { + u.uinwater = 0; + docrt(); + vision_full_recalc = 1; + You("find yourself on dry land again!"); + } else if (lava && distu(rx,ry) <= 2) { + int dmg; + You("are hit by molten lava%c", + Fire_resistance ? '.' : '!'); + burn_away_slime(); + dmg = d((Fire_resistance ? 1 : 3), 6); + losehp(Maybe_Half_Phys(dmg), /* lava damage */ + "molten lava", KILLED_BY); + } else if (!fills_up && flags.verbose && + (pushing ? !Blind : cansee(rx,ry))) + pline("It sinks without a trace!"); + } + + /* boulder is now gone */ + if (pushing) delobj(otmp); + else obfree(otmp, (struct obj *)0); + return TRUE; + } + return FALSE; } /* Used for objects which sometimes do special things when dropped; must be @@ -129,112 +129,120 @@ struct obj *obj; int x, y; const char *verb; { - struct trap *t; - struct monst *mtmp; - - if (obj->where != OBJ_FREE) - panic("flooreffects: obj not free"); - - /* make sure things like water_damage() have no pointers to follow */ - obj->nobj = obj->nexthere = (struct obj *)0; - - if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) - return TRUE; - else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 && - (t->ttyp==PIT || t->ttyp==SPIKED_PIT - || t->ttyp==TRAPDOOR || t->ttyp==HOLE)) { - if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || - (u.utrap && u.ux == x && u.uy == y)) { - if (*verb) - pline_The("boulder %s into the pit%s.", - vtense((const char *)0, verb), - (mtmp) ? "" : " with you"); - if (mtmp) { - if (!passes_walls(mtmp->data) && - !throws_rocks(mtmp->data)) { - if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data)) - return FALSE; /* still alive */ - } - mtmp->mtrapped = 0; - } else { - if (!Passes_walls && !throws_rocks(youmonst.data)) { - losehp(Maybe_Half_Phys(rnd(15)), - "squished under a boulder", - NO_KILLER_PREFIX); - return FALSE; /* player remains trapped */ - } else u.utrap = 0; - } - } - if (*verb) { - if (Blind && (x == u.ux) && (y == u.uy)) { - You_hear("a CRASH! beneath you."); - } else if (!Blind && cansee(x, y)) { - pline_The("boulder %s%s.", - t->tseen ? "" : "triggers and ", - t->ttyp == TRAPDOOR ? "plugs a trap door" : - t->ttyp == HOLE ? "plugs a hole" : - "fills a pit"); - } else { - You_hear("a boulder %s.", verb); - } - } - deltrap(t); - useupf(obj, 1L); - bury_objs(x, y); - newsym(x,y); - return TRUE; - } else if (is_lava(x, y)) { - return fire_damage(obj, FALSE, x, y); - } else if (is_pool(x, y)) { - /* Reasonably bulky objects (arbitrary) splash when dropped. - * If you're floating above the water even small things make - * noise. Stuff dropped near fountains always misses */ - if ((Blind || (Levitation || Flying)) && !Deaf && - ((x == u.ux) && (y == u.uy))) { - if (!Underwater) { - if (weight(obj) > 9) { - pline("Splash!"); - } else if (Levitation || Flying) { - pline("Plop!"); - } - } - map_background(x, y, 0); - newsym(x, y); - } - return water_damage(obj, NULL, FALSE) == ER_DESTROYED; - } else if (u.ux == x && u.uy == y && - (t = t_at(x,y)) != 0 && uteetering_at_seen_pit(t)) { - if (Blind && !Deaf) - You_hear("%s tumble downwards.", - the(xname(obj))); - else - pline("%s %s into %s pit.", - The(xname(obj)), otense(obj, "tumble"), - the_your[t->madeby_u]); - } - return FALSE; + struct trap *t; + struct monst *mtmp; + struct obj* otmp; + + if (obj->where != OBJ_FREE) + panic("flooreffects: obj not free"); + + /* make sure things like water_damage() have no pointers to follow */ + obj->nobj = obj->nexthere = (struct obj *)0; + + if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) + return TRUE; + else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 && + (t->ttyp==PIT || t->ttyp==SPIKED_PIT + || t->ttyp==TRAPDOOR || t->ttyp==HOLE)) { + if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || + (u.utrap && u.ux == x && u.uy == y)) { + if (*verb) + pline_The("boulder %s into the pit%s.", + vtense((const char *)0, verb), + (mtmp) ? "" : " with you"); + if (mtmp) { + if (!passes_walls(mtmp->data) && + !throws_rocks(mtmp->data)) { + if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data)) + return FALSE; /* still alive */ + } + mtmp->mtrapped = 0; + } else { + if (!Passes_walls && !throws_rocks(youmonst.data)) { + losehp(Maybe_Half_Phys(rnd(15)), + "squished under a boulder", + NO_KILLER_PREFIX); + return FALSE; /* player remains trapped */ + } else u.utrap = 0; + } + } + if (*verb) { + if (Blind && (x == u.ux) && (y == u.uy)) { + You_hear("a CRASH! beneath you."); + } else if (!Blind && cansee(x, y)) { + pline_The("boulder %s%s.", + t->tseen ? "" : "triggers and ", + t->ttyp == TRAPDOOR ? "plugs a trap door" : + t->ttyp == HOLE ? "plugs a hole" : + "fills a pit"); + } else { + You_hear("a boulder %s.", verb); + } + } + deltrap(t); + useupf(obj, 1L); + bury_objs(x, y); + newsym(x,y); + return TRUE; + } else if (is_lava(x, y)) { + return fire_damage(obj, FALSE, x, y); + } else if (is_pool(x, y)) { + /* Reasonably bulky objects (arbitrary) splash when dropped. + * If you're floating above the water even small things make + * noise. Stuff dropped near fountains always misses */ + if ((Blind || (Levitation || Flying)) && !Deaf && + ((x == u.ux) && (y == u.uy))) { + if (!Underwater) { + if (weight(obj) > 9) { + pline("Splash!"); + } else if (Levitation || Flying) { + pline("Plop!"); + } + } + map_background(x, y, 0); + newsym(x, y); + } + return water_damage(obj, NULL, FALSE) == ER_DESTROYED; + } else if (u.ux == x && u.uy == y && + (t = t_at(x,y)) != 0 && uteetering_at_seen_pit(t)) { + if (Blind && !Deaf) + You_hear("%s tumble downwards.", + the(xname(obj))); + else + pline("%s %s into %s pit.", + The(xname(obj)), otense(obj, "tumble"), + the_your[t->madeby_u]); + } else if (obj->globby) { + /* Globby things like puddings might stick together */ + while (obj && (otmp = obj_nexto_xy(obj->otyp, x, y, obj->o_id)) != (struct obj*)0) { + pline("The %s coalesce.", makeplural(obj_typename(obj->otyp))); + obj_meld(&obj, &otmp); + return (obj == NULL); + } + } + return FALSE; } void doaltarobj(obj) /* obj is an object dropped on an altar */ - register struct obj *obj; + register struct obj *obj; { - if (Blind) - return; - - /* KMH, conduct */ - u.uconduct.gnostic++; - - if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) { - There("is %s flash as %s %s the altar.", - an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), - doname(obj), otense(obj, "hit")); - if (!Hallucination) obj->bknown = 1; - } else { - pline("%s %s on the altar.", Doname2(obj), - otense(obj, "land")); - obj->bknown = 1; - } + if (Blind) + return; + + /* KMH, conduct */ + u.uconduct.gnostic++; + + if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) { + There("is %s flash as %s %s the altar.", + an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), + doname(obj), otense(obj, "hit")); + if (!Hallucination) obj->bknown = 1; + } else { + pline("%s %s on the altar.", Doname2(obj), + otense(obj, "land")); + obj->bknown = 1; + } } STATIC_OVL @@ -242,9 +250,9 @@ void trycall(obj) register struct obj *obj; { - if(!objects[obj->otyp].oc_name_known && - !objects[obj->otyp].oc_uname) - docall(obj); + if(!objects[obj->otyp].oc_name_known && + !objects[obj->otyp].oc_uname) + docall(obj); } STATIC_OVL @@ -252,141 +260,141 @@ void dosinkring(obj) /* obj is a ring being dropped over a kitchen sink */ register struct obj *obj; { - register struct obj *otmp,*otmp2; - register boolean ideed = TRUE; - - You("drop %s down the drain.", doname(obj)); - obj->in_use = TRUE; /* block free identification via interrupt */ - switch(obj->otyp) { /* effects that can be noticed without eyes */ - case RIN_SEARCHING: - You("thought %s got lost in the sink, but there it is!", - yname(obj)); - goto giveback; - case RIN_SLOW_DIGESTION: - pline_The("ring is regurgitated!"); + register struct obj *otmp,*otmp2; + register boolean ideed = TRUE; + + You("drop %s down the drain.", doname(obj)); + obj->in_use = TRUE; /* block free identification via interrupt */ + switch(obj->otyp) { /* effects that can be noticed without eyes */ + case RIN_SEARCHING: + You("thought %s got lost in the sink, but there it is!", + yname(obj)); + goto giveback; + case RIN_SLOW_DIGESTION: + pline_The("ring is regurgitated!"); giveback: - obj->in_use = FALSE; - dropx(obj); - trycall(obj); - return; - case RIN_LEVITATION: - pline_The("sink quivers upward for a moment."); - break; - case RIN_POISON_RESISTANCE: - You("smell rotten %s.", makeplural(fruitname(FALSE))); - break; - case RIN_AGGRAVATE_MONSTER: - pline("Several flies buzz angrily around the sink."); - break; - case RIN_SHOCK_RESISTANCE: - pline("Static electricity surrounds the sink."); - break; - case RIN_CONFLICT: - You_hear("loud noises coming from the drain."); - break; - case RIN_SUSTAIN_ABILITY: /* KMH */ - pline_The("water flow seems fixed."); - break; - case RIN_GAIN_STRENGTH: - pline_The("water flow seems %ser now.", - (obj->spe<0) ? "weak" : "strong"); - break; - case RIN_GAIN_CONSTITUTION: - pline_The("water flow seems %ser now.", - (obj->spe<0) ? "less" : "great"); - break; - case RIN_INCREASE_ACCURACY: /* KMH */ - pline_The("water flow %s the drain.", - (obj->spe<0) ? "misses" : "hits"); - break; - case RIN_INCREASE_DAMAGE: - pline_The("water's force seems %ser now.", - (obj->spe<0) ? "small" : "great"); - break; - case RIN_HUNGER: - ideed = FALSE; - for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { - otmp2 = otmp->nexthere; - if (otmp != uball && otmp != uchain && - !obj_resists(otmp, 1, 99)) { - if (!Blind) { - pline("Suddenly, %s %s from the sink!", - doname(otmp), otense(otmp, "vanish")); - ideed = TRUE; - } - delobj(otmp); - } - } - break; - case MEAT_RING: - /* Not the same as aggravate monster; besides, it's obvious. */ - pline("Several flies buzz around the sink."); - break; - default: - ideed = FALSE; - break; - } - if(!Blind && !ideed && obj->otyp != RIN_HUNGER) { - ideed = TRUE; - switch(obj->otyp) { /* effects that need eyes */ - case RIN_ADORNMENT: - pline_The("faucets flash brightly for a moment."); - break; - case RIN_REGENERATION: - pline_The("sink looks as good as new."); - break; - case RIN_INVISIBILITY: - You("don't see anything happen to the sink."); - break; - case RIN_FREE_ACTION: - You_see("the ring slide right down the drain!"); - break; - case RIN_SEE_INVISIBLE: - You_see("some air in the sink."); - break; - case RIN_STEALTH: - pline_The("sink seems to blend into the floor for a moment."); - break; - case RIN_FIRE_RESISTANCE: - pline_The("hot water faucet flashes brightly for a moment."); - break; - case RIN_COLD_RESISTANCE: - pline_The("cold water faucet flashes brightly for a moment."); - break; - case RIN_PROTECTION_FROM_SHAPE_CHAN: - pline_The("sink looks nothing like a fountain."); - break; - case RIN_PROTECTION: - pline_The("sink glows %s for a moment.", - hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER)); - break; - case RIN_WARNING: - pline_The("sink glows %s for a moment.", hcolor(NH_WHITE)); - break; - case RIN_TELEPORTATION: - pline_The("sink momentarily vanishes."); - break; - case RIN_TELEPORT_CONTROL: - pline_The("sink looks like it is being beamed aboard somewhere."); - break; - case RIN_POLYMORPH: - pline_The("sink momentarily looks like a fountain."); - break; - case RIN_POLYMORPH_CONTROL: - pline_The("sink momentarily looks like a regularly erupting geyser."); - break; - } - } - if(ideed) - trycall(obj); - else - You_hear("the ring bouncing down the drainpipe."); - if (!rn2(20)) { - pline_The("sink backs up, leaving %s.", doname(obj)); - obj->in_use = FALSE; - dropx(obj); - } else - useup(obj); + obj->in_use = FALSE; + dropx(obj); + trycall(obj); + return; + case RIN_LEVITATION: + pline_The("sink quivers upward for a moment."); + break; + case RIN_POISON_RESISTANCE: + You("smell rotten %s.", makeplural(fruitname(FALSE))); + break; + case RIN_AGGRAVATE_MONSTER: + pline("Several flies buzz angrily around the sink."); + break; + case RIN_SHOCK_RESISTANCE: + pline("Static electricity surrounds the sink."); + break; + case RIN_CONFLICT: + You_hear("loud noises coming from the drain."); + break; + case RIN_SUSTAIN_ABILITY: /* KMH */ + pline_The("water flow seems fixed."); + break; + case RIN_GAIN_STRENGTH: + pline_The("water flow seems %ser now.", + (obj->spe<0) ? "weak" : "strong"); + break; + case RIN_GAIN_CONSTITUTION: + pline_The("water flow seems %ser now.", + (obj->spe<0) ? "less" : "great"); + break; + case RIN_INCREASE_ACCURACY: /* KMH */ + pline_The("water flow %s the drain.", + (obj->spe<0) ? "misses" : "hits"); + break; + case RIN_INCREASE_DAMAGE: + pline_The("water's force seems %ser now.", + (obj->spe<0) ? "small" : "great"); + break; + case RIN_HUNGER: + ideed = FALSE; + for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { + otmp2 = otmp->nexthere; + if (otmp != uball && otmp != uchain && + !obj_resists(otmp, 1, 99)) { + if (!Blind) { + pline("Suddenly, %s %s from the sink!", + doname(otmp), otense(otmp, "vanish")); + ideed = TRUE; + } + delobj(otmp); + } + } + break; + case MEAT_RING: + /* Not the same as aggravate monster; besides, it's obvious. */ + pline("Several flies buzz around the sink."); + break; + default: + ideed = FALSE; + break; + } + if(!Blind && !ideed && obj->otyp != RIN_HUNGER) { + ideed = TRUE; + switch(obj->otyp) { /* effects that need eyes */ + case RIN_ADORNMENT: + pline_The("faucets flash brightly for a moment."); + break; + case RIN_REGENERATION: + pline_The("sink looks as good as new."); + break; + case RIN_INVISIBILITY: + You("don't see anything happen to the sink."); + break; + case RIN_FREE_ACTION: + You_see("the ring slide right down the drain!"); + break; + case RIN_SEE_INVISIBLE: + You_see("some air in the sink."); + break; + case RIN_STEALTH: + pline_The("sink seems to blend into the floor for a moment."); + break; + case RIN_FIRE_RESISTANCE: + pline_The("hot water faucet flashes brightly for a moment."); + break; + case RIN_COLD_RESISTANCE: + pline_The("cold water faucet flashes brightly for a moment."); + break; + case RIN_PROTECTION_FROM_SHAPE_CHAN: + pline_The("sink looks nothing like a fountain."); + break; + case RIN_PROTECTION: + pline_The("sink glows %s for a moment.", + hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER)); + break; + case RIN_WARNING: + pline_The("sink glows %s for a moment.", hcolor(NH_WHITE)); + break; + case RIN_TELEPORTATION: + pline_The("sink momentarily vanishes."); + break; + case RIN_TELEPORT_CONTROL: + pline_The("sink looks like it is being beamed aboard somewhere."); + break; + case RIN_POLYMORPH: + pline_The("sink momentarily looks like a fountain."); + break; + case RIN_POLYMORPH_CONTROL: + pline_The("sink momentarily looks like a regularly erupting geyser."); + break; + } + } + if(ideed) + trycall(obj); + else + You_hear("the ring bouncing down the drainpipe."); + if (!rn2(20)) { + pline_The("sink backs up, leaving %s.", doname(obj)); + obj->in_use = FALSE; + dropx(obj); + } else + useup(obj); } /* some common tests when trying to drop or throw items */ @@ -395,41 +403,41 @@ canletgo(obj,word) register struct obj *obj; register const char *word; { - if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){ - if (*word) - Norep("You cannot %s %s you are wearing.",word, - something); - return(FALSE); - } - if (obj->otyp == LOADSTONE && obj->cursed) { - /* getobj() kludge sets corpsenm to user's specified count - when refusing to split a stack of cursed loadstones */ - if (*word) { - /* getobj() ignores a count for throwing since that is - implicitly forced to be 1; replicate its kludge... */ - if (!strcmp(word, "throw") && obj->quan > 1L) - obj->corpsenm = 1; - pline("For some reason, you cannot %s%s the stone%s!", - word, obj->corpsenm ? " any of" : "", - plur(obj->quan)); - } - obj->corpsenm = 0; /* reset */ - obj->bknown = 1; - return(FALSE); - } - if (obj->otyp == LEASH && obj->leashmon != 0) { - if (*word) - pline_The("leash is tied around your %s.", - body_part(HAND)); - return(FALSE); - } - if (obj->owornmask & W_SADDLE) { - if (*word) - You("cannot %s %s you are sitting on.", word, - something); - return (FALSE); - } - return(TRUE); + if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){ + if (*word) + Norep("You cannot %s %s you are wearing.",word, + something); + return(FALSE); + } + if (obj->otyp == LOADSTONE && obj->cursed) { + /* getobj() kludge sets corpsenm to user's specified count + when refusing to split a stack of cursed loadstones */ + if (*word) { + /* getobj() ignores a count for throwing since that is + implicitly forced to be 1; replicate its kludge... */ + if (!strcmp(word, "throw") && obj->quan > 1L) + obj->corpsenm = 1; + pline("For some reason, you cannot %s%s the stone%s!", + word, obj->corpsenm ? " any of" : "", + plur(obj->quan)); + } + obj->corpsenm = 0; /* reset */ + obj->bknown = 1; + return(FALSE); + } + if (obj->otyp == LEASH && obj->leashmon != 0) { + if (*word) + pline_The("leash is tied around your %s.", + body_part(HAND)); + return(FALSE); + } + if (obj->owornmask & W_SADDLE) { + if (*word) + You("cannot %s %s you are sitting on.", word, + something); + return (FALSE); + } + return(TRUE); } STATIC_PTR @@ -437,60 +445,60 @@ int drop(obj) register struct obj *obj; { - if(!obj) return(0); - if(!canletgo(obj,"drop")) - return(0); - if(obj == uwep) { - if(welded(uwep)) { - weldmsg(obj); - return(0); - } - setuwep((struct obj *)0); - } - if(obj == uquiver) { - setuqwep((struct obj *)0); - } - if (obj == uswapwep) { - setuswapwep((struct obj *)0); - } - - if (u.uswallow) { - /* barrier between you and the floor */ - if(flags.verbose) - { - char buf[BUFSZ]; - - /* doname can call s_suffix, reusing its buffer */ - Strcpy(buf, s_suffix(mon_nam(u.ustuck))); - You("drop %s into %s %s.", doname(obj), buf, - mbodypart(u.ustuck, STOMACH)); - } - } else { - if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) && - IS_SINK(levl[u.ux][u.uy].typ)) { - dosinkring(obj); - return(1); - } - if (!can_reach_floor(TRUE)) { - /* we might be levitating due to #invoke Heart of Ahriman; - if so, levitation would end during call to freeinv() - and we want hitfloor() to happen before float_down() */ - boolean levhack = finesse_ahriman(obj); - - if (levhack) ELevitation = W_ART; /* other than W_ARTI */ - if(flags.verbose) You("drop %s.", doname(obj)); - /* Ensure update when we drop gold objects */ - if (obj->oclass == COIN_CLASS) context.botl = 1; - freeinv(obj); - hitfloor(obj); - if (levhack) float_down(I_SPECIAL|TIMEOUT, W_ARTI|W_ART); - return(1); - } - if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose) - You("drop %s.", doname(obj)); - } - dropx(obj); - return(1); + if(!obj) return(0); + if(!canletgo(obj,"drop")) + return(0); + if(obj == uwep) { + if(welded(uwep)) { + weldmsg(obj); + return(0); + } + setuwep((struct obj *)0); + } + if(obj == uquiver) { + setuqwep((struct obj *)0); + } + if (obj == uswapwep) { + setuswapwep((struct obj *)0); + } + + if (u.uswallow) { + /* barrier between you and the floor */ + if(flags.verbose) + { + char buf[BUFSZ]; + + /* doname can call s_suffix, reusing its buffer */ + Strcpy(buf, s_suffix(mon_nam(u.ustuck))); + You("drop %s into %s %s.", doname(obj), buf, + mbodypart(u.ustuck, STOMACH)); + } + } else { + if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) && + IS_SINK(levl[u.ux][u.uy].typ)) { + dosinkring(obj); + return(1); + } + if (!can_reach_floor(TRUE)) { + /* we might be levitating due to #invoke Heart of Ahriman; + if so, levitation would end during call to freeinv() + and we want hitfloor() to happen before float_down() */ + boolean levhack = finesse_ahriman(obj); + + if (levhack) ELevitation = W_ART; /* other than W_ARTI */ + if(flags.verbose) You("drop %s.", doname(obj)); + /* Ensure update when we drop gold objects */ + if (obj->oclass == COIN_CLASS) context.botl = 1; + freeinv(obj); + hitfloor(obj); + if (levhack) float_down(I_SPECIAL|TIMEOUT, W_ARTI|W_ART); + return(1); + } + if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose) + You("drop %s.", doname(obj)); + } + dropx(obj); + return(1); } /* dropx - take dropped item out of inventory; @@ -503,12 +511,12 @@ register struct obj *obj; /* Ensure update when we drop gold objects */ if (obj->oclass == COIN_CLASS) context.botl = 1; freeinv(obj); - if (!u.uswallow) { - if (ship_object(obj, u.ux, u.uy, FALSE)) return; - if (IS_ALTAR(levl[u.ux][u.uy].typ)) - doaltarobj(obj); /* set bknown */ - } - dropy(obj); + if (!u.uswallow) { + if (ship_object(obj, u.ux, u.uy, FALSE)) return; + if (IS_ALTAR(levl[u.ux][u.uy].typ)) + doaltarobj(obj); /* set bknown */ + } + dropy(obj); } /* dropy - put dropped object at its destination; called from lots of places */ @@ -516,7 +524,7 @@ void dropy(obj) struct obj *obj; { - dropz(obj, FALSE); + dropz(obj, FALSE); } /* dropz - really put dropped object at its destination... */ @@ -525,61 +533,61 @@ dropz(obj, with_impact) struct obj *obj; boolean with_impact; { - if (obj == uwep) setuwep((struct obj *)0); - if (obj == uquiver) setuqwep((struct obj *)0); - if (obj == uswapwep) setuswapwep((struct obj *)0); - - if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return; - /* uswallow check done by GAN 01/29/87 */ - if(u.uswallow) { - boolean could_petrify = FALSE; - boolean could_poly = FALSE; - boolean could_slime = FALSE; - boolean could_grow = FALSE; - boolean could_heal = FALSE; - - if (obj != uball) { /* mon doesn't pick up ball */ - if (obj->otyp == CORPSE) { - could_petrify = touch_petrifies(&mons[obj->corpsenm]); - could_poly = polyfodder(obj); - could_slime = (obj->corpsenm == PM_GREEN_SLIME); - could_grow = (obj->corpsenm == PM_WRAITH); - could_heal = (obj->corpsenm == PM_NURSE); - } - (void) mpickobj(u.ustuck,obj); - if (is_animal(u.ustuck->data)) { - if (could_poly || could_slime) { - (void) newcham(u.ustuck, - could_poly ? (struct permonst *)0 : - &mons[PM_GREEN_SLIME], - FALSE, could_slime); - delobj(obj); /* corpse is digested */ - } else if (could_petrify) { - minstapetrify(u.ustuck, TRUE); - /* Don't leave a cockatrice corpse in a statue */ - if (!u.uswallow) delobj(obj); - } else if (could_grow) { - (void) grow_up(u.ustuck, (struct monst *)0); - delobj(obj); /* corpse is digested */ - } else if (could_heal) { - u.ustuck->mhp = u.ustuck->mhpmax; - delobj(obj); /* corpse is digested */ - } - } - } - } else { - place_object(obj, u.ux, u.uy); - if (with_impact) - container_impact_dmg(obj, u.ux, u.uy); - if (obj == uball) - drop_ball(u.ux,u.uy); - else if (level.flags.has_shop) - sellobj(obj, u.ux, u.uy); - stackobj(obj); - if(Blind && Levitation) - map_object(obj, 0); - newsym(u.ux,u.uy); /* remap location under self */ - } + if (obj == uwep) setuwep((struct obj *)0); + if (obj == uquiver) setuqwep((struct obj *)0); + if (obj == uswapwep) setuswapwep((struct obj *)0); + + if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return; + /* uswallow check done by GAN 01/29/87 */ + if(u.uswallow) { + boolean could_petrify = FALSE; + boolean could_poly = FALSE; + boolean could_slime = FALSE; + boolean could_grow = FALSE; + boolean could_heal = FALSE; + + if (obj != uball) { /* mon doesn't pick up ball */ + if (obj->otyp == CORPSE) { + could_petrify = touch_petrifies(&mons[obj->corpsenm]); + could_poly = polyfodder(obj); + could_slime = (obj->corpsenm == PM_GREEN_SLIME); + could_grow = (obj->corpsenm == PM_WRAITH); + could_heal = (obj->corpsenm == PM_NURSE); + } + (void) mpickobj(u.ustuck,obj); + if (is_animal(u.ustuck->data)) { + if (could_poly || could_slime) { + (void) newcham(u.ustuck, + could_poly ? (struct permonst *)0 : + &mons[PM_GREEN_SLIME], + FALSE, could_slime); + delobj(obj); /* corpse is digested */ + } else if (could_petrify) { + minstapetrify(u.ustuck, TRUE); + /* Don't leave a cockatrice corpse in a statue */ + if (!u.uswallow) delobj(obj); + } else if (could_grow) { + (void) grow_up(u.ustuck, (struct monst *)0); + delobj(obj); /* corpse is digested */ + } else if (could_heal) { + u.ustuck->mhp = u.ustuck->mhpmax; + delobj(obj); /* corpse is digested */ + } + } + } + } else { + place_object(obj, u.ux, u.uy); + if (with_impact) + container_impact_dmg(obj, u.ux, u.uy); + if (obj == uball) + drop_ball(u.ux,u.uy); + else if (level.flags.has_shop) + sellobj(obj, u.ux, u.uy); + stackobj(obj); + if(Blind && Levitation) + map_object(obj, 0); + newsym(u.ux,u.uy); /* remap location under self */ + } } /* things that must change when not held; recurse into containers. @@ -588,48 +596,48 @@ void obj_no_longer_held(obj) struct obj *obj; { - if (!obj) { - return; - } else if (Has_contents(obj)) { - struct obj *contents; - - for (contents = obj->cobj; contents; contents = contents->nobj) - obj_no_longer_held(contents); - } - switch (obj->otyp) { - case CRYSKNIFE: - /* Normal crysknife reverts to worm tooth when not held by hero - * or monster; fixed crysknife has only 10% chance of reverting. - * When a stack of the latter is involved, it could be worthwhile - * to give each individual crysknife its own separate 10% chance, - * but we aren't in any position to handle stack splitting here. - */ - if (!obj->oerodeproof || !rn2(10)) { - /* if monsters aren't moving, assume player is responsible */ - if (!context.mon_moving && !program_state.gameover) - costly_alteration(obj, COST_DEGRD); - obj->otyp = WORM_TOOTH; - obj->oerodeproof = 0; - } - break; - } + if (!obj) { + return; + } else if (Has_contents(obj)) { + struct obj *contents; + + for (contents = obj->cobj; contents; contents = contents->nobj) + obj_no_longer_held(contents); + } + switch (obj->otyp) { + case CRYSKNIFE: + /* Normal crysknife reverts to worm tooth when not held by hero + * or monster; fixed crysknife has only 10% chance of reverting. + * When a stack of the latter is involved, it could be worthwhile + * to give each individual crysknife its own separate 10% chance, + * but we aren't in any position to handle stack splitting here. + */ + if (!obj->oerodeproof || !rn2(10)) { + /* if monsters aren't moving, assume player is responsible */ + if (!context.mon_moving && !program_state.gameover) + costly_alteration(obj, COST_DEGRD); + obj->otyp = WORM_TOOTH; + obj->oerodeproof = 0; + } + break; + } } /* 'D' command: drop several things */ int doddrop() { - int result = 0; + int result = 0; - add_valid_menu_class(0); /* clear any classes already there */ - if (*u.ushops) sellobj_state(SELL_DELIBERATE); - if (flags.menu_style != MENU_TRADITIONAL || - (result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1) - result = menu_drop(result); - if (*u.ushops) sellobj_state(SELL_NORMAL); - reset_occupations(); + add_valid_menu_class(0); /* clear any classes already there */ + if (*u.ushops) sellobj_state(SELL_DELIBERATE); + if (flags.menu_style != MENU_TRADITIONAL || + (result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1) + result = menu_drop(result); + if (*u.ushops) sellobj_state(SELL_NORMAL); + reset_occupations(); - return result; + return result; } /* Drop things from the hero's inventory, using a menu. */ @@ -645,98 +653,98 @@ int retry; boolean drop_everything = FALSE; if (retry) { - all_categories = (retry == -2); + all_categories = (retry == -2); } else if (flags.menu_style == MENU_FULL) { - all_categories = FALSE; - n = query_category("Drop what type of items?", - invent, - UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | - BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, - &pick_list, PICK_ANY); - if (!n) goto drop_done; - for (i = 0; i < n; i++) { - if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) - all_categories = TRUE; - else if (pick_list[i].item.a_int == 'A') - drop_everything = TRUE; - else - add_valid_menu_class(pick_list[i].item.a_int); - } - free((genericptr_t) pick_list); + all_categories = FALSE; + n = query_category("Drop what type of items?", + invent, + UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | + BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, + &pick_list, PICK_ANY); + if (!n) goto drop_done; + for (i = 0; i < n; i++) { + if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) + all_categories = TRUE; + else if (pick_list[i].item.a_int == 'A') + drop_everything = TRUE; + else + add_valid_menu_class(pick_list[i].item.a_int); + } + free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { - unsigned ggoresults = 0; - all_categories = FALSE; - /* Gather valid classes via traditional NetHack method */ - i = ggetobj("drop", drop, 0, TRUE, &ggoresults); - if (i == -2) all_categories = TRUE; - if (ggoresults & ALL_FINISHED) { - n_dropped = i; - goto drop_done; - } + unsigned ggoresults = 0; + all_categories = FALSE; + /* Gather valid classes via traditional NetHack method */ + i = ggetobj("drop", drop, 0, TRUE, &ggoresults); + if (i == -2) all_categories = TRUE; + if (ggoresults & ALL_FINISHED) { + n_dropped = i; + goto drop_done; + } } if (drop_everything) { - /* - * Dropping a burning potion of oil while levitating can cause - * an explosion which might destroy some of hero's inventory, - * so the old code - * for (otmp = invent; otmp; otmp = otmp2) { - * otmp2 = otmp->nobj; - * n_dropped += drop(otmp); - * } - * was unreliable and could lead to an "object lost" panic. - * - * Use the bypass bit to mark items already processed (hence - * not droppable) and rescan inventory until no unbypassed - * items remain. - */ - bypass_objlist(invent, FALSE); /* clear bypass bit for invent */ - while ((otmp = nxt_unbypassed_obj(invent)) != 0) - n_dropped += drop(otmp); - /* we might not have dropped everything (worn armor, welded weapon, - cursed loadstones), so reset any remaining inventory to normal */ - bypass_objlist(invent, FALSE); + /* + * Dropping a burning potion of oil while levitating can cause + * an explosion which might destroy some of hero's inventory, + * so the old code + * for (otmp = invent; otmp; otmp = otmp2) { + * otmp2 = otmp->nobj; + * n_dropped += drop(otmp); + * } + * was unreliable and could lead to an "object lost" panic. + * + * Use the bypass bit to mark items already processed (hence + * not droppable) and rescan inventory until no unbypassed + * items remain. + */ + bypass_objlist(invent, FALSE); /* clear bypass bit for invent */ + while ((otmp = nxt_unbypassed_obj(invent)) != 0) + n_dropped += drop(otmp); + /* we might not have dropped everything (worn armor, welded weapon, + cursed loadstones), so reset any remaining inventory to normal */ + bypass_objlist(invent, FALSE); } else { - /* should coordinate with perm invent, maybe not show worn items */ - n = query_objlist("What would you like to drop?", invent, - USE_INVLET|INVORDER_SORT, &pick_list, - PICK_ANY, all_categories ? allow_all : allow_category); - if (n > 0) { - /* - * picklist[] contains a set of pointers into inventory, but - * as soon as something gets dropped, they might become stale - * (see the drop_everything code above for an explanation). - * Just checking to see whether one is still in the invent - * chain is not sufficient validation since destroyed items - * will be freed and items we've split here might have already - * reused that memory and put the same pointer value back into - * invent. Ditto for using invlet to validate. So we start - * by setting bypass on all of invent, then check each pointer - * to verify that it is in invent and has that bit set. - */ - bypass_objlist(invent, TRUE); - for (i = 0; i < n; i++) { - otmp = pick_list[i].item.a_obj; - for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj) - if (otmp2 == otmp) break; - if (!otmp2 || !otmp2->bypass) continue; - /* found next selected invent item */ - cnt = pick_list[i].count; - if (cnt < otmp->quan) { - if (welded(otmp)) { - ; /* don't split */ - } else if (otmp->otyp == LOADSTONE && otmp->cursed) { - /* same kludge as getobj(), for canletgo()'s use */ - otmp->corpsenm = (int) cnt; /* don't split */ - } else { - otmp = splitobj(otmp, cnt); - } - } - n_dropped += drop(otmp); - } - bypass_objlist(invent, FALSE); /* reset invent to normal */ - free((genericptr_t) pick_list); - } + /* should coordinate with perm invent, maybe not show worn items */ + n = query_objlist("What would you like to drop?", invent, + USE_INVLET|INVORDER_SORT, &pick_list, + PICK_ANY, all_categories ? allow_all : allow_category); + if (n > 0) { + /* + * picklist[] contains a set of pointers into inventory, but + * as soon as something gets dropped, they might become stale + * (see the drop_everything code above for an explanation). + * Just checking to see whether one is still in the invent + * chain is not sufficient validation since destroyed items + * will be freed and items we've split here might have already + * reused that memory and put the same pointer value back into + * invent. Ditto for using invlet to validate. So we start + * by setting bypass on all of invent, then check each pointer + * to verify that it is in invent and has that bit set. + */ + bypass_objlist(invent, TRUE); + for (i = 0; i < n; i++) { + otmp = pick_list[i].item.a_obj; + for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj) + if (otmp2 == otmp) break; + if (!otmp2 || !otmp2->bypass) continue; + /* found next selected invent item */ + cnt = pick_list[i].count; + if (cnt < otmp->quan) { + if (welded(otmp)) { + ; /* don't split */ + } else if (otmp->otyp == LOADSTONE && otmp->cursed) { + /* same kludge as getobj(), for canletgo()'s use */ + otmp->corpsenm = (int) cnt; /* don't split */ + } else { + otmp = splitobj(otmp, cnt); + } + } + n_dropped += drop(otmp); + } + bypass_objlist(invent, FALSE); /* reset invent to normal */ + free((genericptr_t) pick_list); + } } drop_done: @@ -749,167 +757,167 @@ static NEARDATA boolean at_ladder = FALSE; int dodown() { - struct trap *trap = 0; - boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) || - (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)), - ladder_down = (u.ux == xdnladder && u.uy == ydnladder); - - if(!youmonst.data->mmove) { - You("are rooted %s.", - Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? - "in place" : "to the ground"); - nomul(0); - return 1; - } - - if (stucksteed(TRUE)) { - return 0; - } - /* Levitation might be blocked, but player can still use '>' to - turn off controlled levitaiton */ - if (HLevitation || ELevitation) { - if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) { - /* end controlled levitation */ - if (ELevitation & W_ARTI) { - struct obj *obj; - - for(obj = invent; obj; obj = obj->nobj) { - if (obj->oartifact && - artifact_has_invprop(obj, LEVITATION)) { - if (obj->age < monstermoves) - obj->age = monstermoves; - obj->age += rnz(100); - } - } - } - if (float_down(I_SPECIAL|TIMEOUT, W_ARTI)) { - return 1; /* came down, so moved */ - } else if (!HLevitation && !ELevitation) { - Your("latent levitation ceases."); - return 1; /* did something, effectively moved */ - } - } - if (BLevitation) { - ; /* weren't actually floating after all */ - } else if (Blind) { - /* Avoid alerting player to an unknown stair or ladder. - * Changes the message for a covered, known staircase - * too; staircase knowledge is not stored anywhere. - */ - if (stairs_down) - stairs_down = - (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnstair); - else if (ladder_down) - ladder_down = - (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnladder); - } - floating_above(stairs_down ? "stairs" : ladder_down ? - "ladder" : surface(u.ux, u.uy)); - return (0); /* didn't move */ - } - if (!stairs_down && !ladder_down) { - trap = t_at(u.ux,u.uy); - if (trap && uteetering_at_seen_pit(trap)) { - dotrap(trap, TOOKPLUNGE); - return(1); - } else if (!trap || - (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE) || - !Can_fall_thru(&u.uz) || !trap->tseen) { - if (flags.autodig && !context.nopick && - uwep && is_pick(uwep)) { - return use_pick_axe2(uwep); - } else { - You_cant("go down here."); - return(0); - } - } - } - if(u.ustuck) { - You("are %s, and cannot go down.", - !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? - "swallowed" : "engulfed"); - return(1); - } - if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) { - You("are standing at the gate to Gehennom."); - pline("Unspeakable cruelty and harm lurk down there."); - if (yn("Are you sure you want to enter?") != 'y') - return(0); - else pline("So be it."); - u.uevent.gehennom_entered = 1; /* don't ask again */ - } - - if(!next_to_u()) { - You("are held back by your pet!"); - return(0); - } - - if (trap) - You("%s %s.", Flying ? "fly" : locomotion(youmonst.data, "jump"), - trap->ttyp == HOLE ? "down the hole" : "through the trap door"); - - if (trap && Is_stronghold(&u.uz)) { - goto_hell(FALSE, TRUE); - } else { - at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); - next_level(!trap); - at_ladder = FALSE; - } - return(1); + struct trap *trap = 0; + boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) || + (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)), + ladder_down = (u.ux == xdnladder && u.uy == ydnladder); + + if(!youmonst.data->mmove) { + You("are rooted %s.", + Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? + "in place" : "to the ground"); + nomul(0); + return 1; + } + + if (stucksteed(TRUE)) { + return 0; + } + /* Levitation might be blocked, but player can still use '>' to + turn off controlled levitaiton */ + if (HLevitation || ELevitation) { + if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) { + /* end controlled levitation */ + if (ELevitation & W_ARTI) { + struct obj *obj; + + for(obj = invent; obj; obj = obj->nobj) { + if (obj->oartifact && + artifact_has_invprop(obj, LEVITATION)) { + if (obj->age < monstermoves) + obj->age = monstermoves; + obj->age += rnz(100); + } + } + } + if (float_down(I_SPECIAL|TIMEOUT, W_ARTI)) { + return 1; /* came down, so moved */ + } else if (!HLevitation && !ELevitation) { + Your("latent levitation ceases."); + return 1; /* did something, effectively moved */ + } + } + if (BLevitation) { + ; /* weren't actually floating after all */ + } else if (Blind) { + /* Avoid alerting player to an unknown stair or ladder. + * Changes the message for a covered, known staircase + * too; staircase knowledge is not stored anywhere. + */ + if (stairs_down) + stairs_down = + (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnstair); + else if (ladder_down) + ladder_down = + (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnladder); + } + floating_above(stairs_down ? "stairs" : ladder_down ? + "ladder" : surface(u.ux, u.uy)); + return (0); /* didn't move */ + } + if (!stairs_down && !ladder_down) { + trap = t_at(u.ux,u.uy); + if (trap && uteetering_at_seen_pit(trap)) { + dotrap(trap, TOOKPLUNGE); + return(1); + } else if (!trap || + (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE) || + !Can_fall_thru(&u.uz) || !trap->tseen) { + if (flags.autodig && !context.nopick && + uwep && is_pick(uwep)) { + return use_pick_axe2(uwep); + } else { + You_cant("go down here."); + return(0); + } + } + } + if(u.ustuck) { + You("are %s, and cannot go down.", + !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? + "swallowed" : "engulfed"); + return(1); + } + if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) { + You("are standing at the gate to Gehennom."); + pline("Unspeakable cruelty and harm lurk down there."); + if (yn("Are you sure you want to enter?") != 'y') + return(0); + else pline("So be it."); + u.uevent.gehennom_entered = 1; /* don't ask again */ + } + + if(!next_to_u()) { + You("are held back by your pet!"); + return(0); + } + + if (trap) + You("%s %s.", Flying ? "fly" : locomotion(youmonst.data, "jump"), + trap->ttyp == HOLE ? "down the hole" : "through the trap door"); + + if (trap && Is_stronghold(&u.uz)) { + goto_hell(FALSE, TRUE); + } else { + at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); + next_level(!trap); + at_ladder = FALSE; + } + return(1); } int doup() { - if(!youmonst.data->mmove) { - You("are rooted %s.", - Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? - "in place" : "to the ground"); - nomul(0); - return 1; - } - - /* "up" to get out of a pit... */ - if (u.utrap && u.utraptype == TT_PIT) { - climb_pit(); - return 1; - } - - if( (u.ux != xupstair || u.uy != yupstair) - && (!xupladder || u.ux != xupladder || u.uy != yupladder) - && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy - || !sstairs.up) - ) { - You_cant("go up here."); - return(0); - } - if (stucksteed(TRUE)) { - return(0); - } - if(u.ustuck) { - You("are %s, and cannot go up.", - !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? - "swallowed" : "engulfed"); - return(1); - } - if(near_capacity() > SLT_ENCUMBER) { - /* No levitation check; inv_weight() already allows for it */ - Your("load is too heavy to climb the %s.", - levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder"); - return(1); - } - if(ledger_no(&u.uz) == 1) { - if (yn("Beware, there will be no return! Still climb?") != 'y') - return(0); - } - if(!next_to_u()) { - You("are held back by your pet!"); - return(0); - } - at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); - prev_level(TRUE); - at_ladder = FALSE; - return(1); + if(!youmonst.data->mmove) { + You("are rooted %s.", + Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? + "in place" : "to the ground"); + nomul(0); + return 1; + } + + /* "up" to get out of a pit... */ + if (u.utrap && u.utraptype == TT_PIT) { + climb_pit(); + return 1; + } + + if( (u.ux != xupstair || u.uy != yupstair) + && (!xupladder || u.ux != xupladder || u.uy != yupladder) + && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy + || !sstairs.up) + ) { + You_cant("go up here."); + return(0); + } + if (stucksteed(TRUE)) { + return(0); + } + if(u.ustuck) { + You("are %s, and cannot go up.", + !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? + "swallowed" : "engulfed"); + return(1); + } + if(near_capacity() > SLT_ENCUMBER) { + /* No levitation check; inv_weight() already allows for it */ + Your("load is too heavy to climb the %s.", + levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder"); + return(1); + } + if(ledger_no(&u.uz) == 1) { + if (yn("Beware, there will be no return! Still climb?") != 'y') + return(0); + } + if(!next_to_u()) { + You("are held back by your pet!"); + return(0); + } + at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); + prev_level(TRUE); + at_ladder = FALSE; + return(1); } d_level save_dlevel = {0, 0}; @@ -918,55 +926,55 @@ d_level save_dlevel = {0, 0}; STATIC_OVL int currentlevel_rewrite() { - register int fd; - char whynot[BUFSZ]; - - /* since level change might be a bit slow, flush any buffered screen - * output (like "you fall through a trap door") */ - mark_synch(); - - fd = create_levelfile(ledger_no(&u.uz), whynot); - if (fd < 0) { - /* - * This is not quite impossible: e.g., we may have - * exceeded our quota. If that is the case then we - * cannot leave this level, and cannot save either. - * Another possibility is that the directory was not - * writable. - */ - pline1(whynot); - return -1; - } + register int fd; + char whynot[BUFSZ]; + + /* since level change might be a bit slow, flush any buffered screen + * output (like "you fall through a trap door") */ + mark_synch(); + + fd = create_levelfile(ledger_no(&u.uz), whynot); + if (fd < 0) { + /* + * This is not quite impossible: e.g., we may have + * exceeded our quota. If that is the case then we + * cannot leave this level, and cannot save either. + * Another possibility is that the directory was not + * writable. + */ + pline1(whynot); + return -1; + } #ifdef MFLOPPY - if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) { - (void) close(fd); - delete_levelfile(ledger_no(&u.uz)); - pline("NetHack is out of disk space for making levels!"); - You("can save, quit, or continue playing."); - return -1; - } + if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) { + (void) close(fd); + delete_levelfile(ledger_no(&u.uz)); + pline("NetHack is out of disk space for making levels!"); + You("can save, quit, or continue playing."); + return -1; + } #endif - return fd; + return fd; } #ifdef INSURANCE void save_currentstate() { - int fd; - - if (flags.ins_chkpt) { - /* write out just-attained level, with pets and everything */ - fd = currentlevel_rewrite(); - if(fd < 0) return; - bufon(fd); - savelev(fd,ledger_no(&u.uz), WRITE_SAVE); - bclose(fd); - } - - /* write out non-level state */ - savestateinlock(); + int fd; + + if (flags.ins_chkpt) { + /* write out just-attained level, with pets and everything */ + fd = currentlevel_rewrite(); + if(fd < 0) return; + bufon(fd); + savelev(fd,ledger_no(&u.uz), WRITE_SAVE); + bclose(fd); + } + + /* write out non-level state */ + savestateinlock(); } #endif @@ -975,8 +983,8 @@ static boolean badspot(x, y) register xchar x, y; { - return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR && - levl[x][y].typ != CORR) || MON_AT(x, y)); + return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR && + levl[x][y].typ != CORR) || MON_AT(x, y)); } */ @@ -985,436 +993,436 @@ goto_level(newlevel, at_stairs, falling, portal) d_level *newlevel; boolean at_stairs, falling, portal; { - int fd, l_idx; - xchar new_ledger; - boolean cant_go_back, - up = (depth(newlevel) < depth(&u.uz)), - newdungeon = (u.uz.dnum != newlevel->dnum), - was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz), - familiar = FALSE; - boolean new = FALSE; /* made a new level? */ - struct monst *mtmp; - char whynot[BUFSZ]; - - if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) - newlevel->dlevel = dunlevs_in_dungeon(newlevel); - if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */ - if (!u.uhave.amulet) return; /* must have the Amulet */ - if (!wizard) /* wizard ^V can bypass Earth level */ - assign_level(newlevel, &earth_level); /* (redundant) */ - } - new_ledger = ledger_no(newlevel); - if (new_ledger <= 0) - done(ESCAPED); /* in fact < 0 is impossible */ - - /* If you have the amulet and are trying to get out of Gehennom, going - * up a set of stairs sometimes does some very strange things! - * Biased against law and towards chaos, but not nearly as strongly - * as it used to be (prior to 3.2.0). - * Odds: old new - * "up" L N C "up" L N C - * +1 75.0 75.0 75.0 +1 75.0 75.0 75.0 - * 0 0.0 12.5 25.0 0 6.25 8.33 12.5 - * -1 8.33 4.17 0.0 -1 6.25 8.33 12.5 - * -2 8.33 4.17 0.0 -2 6.25 8.33 0.0 - * -3 8.33 4.17 0.0 -3 6.25 0.0 0.0 - */ - if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && - (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) { - if (!rn2(4)) { - int odds = 3 + (int)u.ualign.type, /* 2..4 */ - diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */ - - if (diff != 0) { - assign_rnd_level(newlevel, &u.uz, diff); - /* if inside the tower, stay inside */ - if (was_in_W_tower && - !On_W_tower_level(newlevel)) diff = 0; - } - if (diff == 0) - assign_level(newlevel, &u.uz); - - new_ledger = ledger_no(newlevel); - - pline("A mysterious force momentarily surrounds you..."); - if (on_level(newlevel, &u.uz)) { - (void) safe_teleds(FALSE); - (void) next_to_u(); - return; - } else - at_stairs = at_ladder = FALSE; - } - } - - /* Prevent the player from going past the first quest level unless - * (s)he has been given the go-ahead by the leader. - */ - if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) { - pline("A mysterious force prevents you from descending."); - return; - } - - if (on_level(newlevel, &u.uz)) return; /* this can happen */ - - /* tethered movement makes level change while trapped feasible */ - if (u.utrap && u.utraptype == TT_BURIEDBALL) - buried_ball_to_punishment(); /* (before we save/leave old level) */ - - fd = currentlevel_rewrite(); - if (fd < 0) return; - - if (falling) /* assuming this is only trap door or hole */ - impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel); - - check_special_room(TRUE); /* probably was a trap door */ - if (Punished) unplacebc(); - u.utrap = 0; /* needed in level_tele */ - fill_pit(u.ux, u.uy); - u.ustuck = 0; /* idem */ - u.uinwater = 0; - u.uundetected = 0; /* not hidden, even if means are available */ - keepdogs(FALSE); - if (u.uswallow) /* idem */ - u.uswldtim = u.uswallow = 0; - recalc_mapseen(); /* recalculate map overview before we leave the level */ - /* - * We no longer see anything on the level. Make sure that this - * follows u.uswallow set to null since uswallow overrides all - * normal vision. - */ - vision_recalc(2); - - /* - * Save the level we're leaving. If we're entering the endgame, - * we can get rid of all existing levels because they cannot be - * reached any more. We still need to use savelev()'s cleanup - * for the level being left, to recover dynamic memory in use and - * to avoid dangling timers and light sources. - */ - cant_go_back = (newdungeon && In_endgame(newlevel)); - if (!cant_go_back) { - update_mlstmv(); /* current monsters are becoming inactive */ - bufon(fd); /* use buffered output */ - } - savelev(fd, ledger_no(&u.uz), - cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE)); - bclose(fd); - if (cant_go_back) { - /* discard unreachable levels; keep #0 */ - for (l_idx = maxledgerno(); l_idx > 0; --l_idx) - delete_levelfile(l_idx); - /* mark #overview data for all dungeon branches as uninteresting */ - for (l_idx = 0; l_idx < n_dgns; ++l_idx) - remdun_mapseen(l_idx); - } - - if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz)) - assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY); + int fd, l_idx; + xchar new_ledger; + boolean cant_go_back, + up = (depth(newlevel) < depth(&u.uz)), + newdungeon = (u.uz.dnum != newlevel->dnum), + was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz), + familiar = FALSE; + boolean new = FALSE; /* made a new level? */ + struct monst *mtmp; + char whynot[BUFSZ]; + + if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) + newlevel->dlevel = dunlevs_in_dungeon(newlevel); + if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */ + if (!u.uhave.amulet) return; /* must have the Amulet */ + if (!wizard) /* wizard ^V can bypass Earth level */ + assign_level(newlevel, &earth_level); /* (redundant) */ + } + new_ledger = ledger_no(newlevel); + if (new_ledger <= 0) + done(ESCAPED); /* in fact < 0 is impossible */ + + /* If you have the amulet and are trying to get out of Gehennom, going + * up a set of stairs sometimes does some very strange things! + * Biased against law and towards chaos, but not nearly as strongly + * as it used to be (prior to 3.2.0). + * Odds: old new + * "up" L N C "up" L N C + * +1 75.0 75.0 75.0 +1 75.0 75.0 75.0 + * 0 0.0 12.5 25.0 0 6.25 8.33 12.5 + * -1 8.33 4.17 0.0 -1 6.25 8.33 12.5 + * -2 8.33 4.17 0.0 -2 6.25 8.33 0.0 + * -3 8.33 4.17 0.0 -3 6.25 0.0 0.0 + */ + if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && + (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) { + if (!rn2(4)) { + int odds = 3 + (int)u.ualign.type, /* 2..4 */ + diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */ + + if (diff != 0) { + assign_rnd_level(newlevel, &u.uz, diff); + /* if inside the tower, stay inside */ + if (was_in_W_tower && + !On_W_tower_level(newlevel)) diff = 0; + } + if (diff == 0) + assign_level(newlevel, &u.uz); + + new_ledger = ledger_no(newlevel); + + pline("A mysterious force momentarily surrounds you..."); + if (on_level(newlevel, &u.uz)) { + (void) safe_teleds(FALSE); + (void) next_to_u(); + return; + } else + at_stairs = at_ladder = FALSE; + } + } + + /* Prevent the player from going past the first quest level unless + * (s)he has been given the go-ahead by the leader. + */ + if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) { + pline("A mysterious force prevents you from descending."); + return; + } + + if (on_level(newlevel, &u.uz)) return; /* this can happen */ + + /* tethered movement makes level change while trapped feasible */ + if (u.utrap && u.utraptype == TT_BURIEDBALL) + buried_ball_to_punishment(); /* (before we save/leave old level) */ + + fd = currentlevel_rewrite(); + if (fd < 0) return; + + if (falling) /* assuming this is only trap door or hole */ + impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel); + + check_special_room(TRUE); /* probably was a trap door */ + if (Punished) unplacebc(); + u.utrap = 0; /* needed in level_tele */ + fill_pit(u.ux, u.uy); + u.ustuck = 0; /* idem */ + u.uinwater = 0; + u.uundetected = 0; /* not hidden, even if means are available */ + keepdogs(FALSE); + if (u.uswallow) /* idem */ + u.uswldtim = u.uswallow = 0; + recalc_mapseen(); /* recalculate map overview before we leave the level */ + /* + * We no longer see anything on the level. Make sure that this + * follows u.uswallow set to null since uswallow overrides all + * normal vision. + */ + vision_recalc(2); + + /* + * Save the level we're leaving. If we're entering the endgame, + * we can get rid of all existing levels because they cannot be + * reached any more. We still need to use savelev()'s cleanup + * for the level being left, to recover dynamic memory in use and + * to avoid dangling timers and light sources. + */ + cant_go_back = (newdungeon && In_endgame(newlevel)); + if (!cant_go_back) { + update_mlstmv(); /* current monsters are becoming inactive */ + bufon(fd); /* use buffered output */ + } + savelev(fd, ledger_no(&u.uz), + cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE)); + bclose(fd); + if (cant_go_back) { + /* discard unreachable levels; keep #0 */ + for (l_idx = maxledgerno(); l_idx > 0; --l_idx) + delete_levelfile(l_idx); + /* mark #overview data for all dungeon branches as uninteresting */ + for (l_idx = 0; l_idx < n_dgns; ++l_idx) + remdun_mapseen(l_idx); + } + + if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz)) + assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY); #ifdef USE_TILES - substitute_tiles(newlevel); + substitute_tiles(newlevel); #endif - /* record this level transition as a potential seen branch unless using - * some non-standard means of transportation (level teleport). - */ - if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum)) - recbranch_mapseen(&u.uz, newlevel); - assign_level(&u.uz0, &u.uz); - assign_level(&u.uz, newlevel); - assign_level(&u.utolev, newlevel); - u.utotype = 0; - if (dunlev_reached(&u.uz) < dunlev(&u.uz)) - dunlev_reached(&u.uz) = dunlev(&u.uz); - reset_rndmonst(NON_PM); /* u.uz change affects monster generation */ - - /* set default level change destination areas */ - /* the special level code may override these */ - (void) memset((genericptr_t) &updest, 0, sizeof updest); - (void) memset((genericptr_t) &dndest, 0, sizeof dndest); - - if (!(level_info[new_ledger].flags & LFILE_EXISTS)) { - /* entering this level for first time; make it now */ - if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) { - impossible("goto_level: returning to discarded level?"); - level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED); - } - mklev(); - new = TRUE; /* made the level */ - } else { - /* returning to previously visited level; reload it */ - fd = open_levelfile(new_ledger, whynot); - if (fd < 0) { - pline1(whynot); - pline("Probably someone removed it."); - Strcpy(killer.name, whynot); - done(TRICKED); - /* we'll reach here if running in wizard mode */ - error("Cannot continue this game."); - } - minit(); /* ZEROCOMP */ - getlev(fd, hackpid, new_ledger, FALSE); - (void) close(fd); - oinit(); /* reassign level dependent obj probabilities */ - } - /* do this prior to level-change pline messages */ - vision_reset(); /* clear old level's line-of-sight */ - vision_full_recalc = 0; /* don't let that reenable vision yet */ - flush_screen(-1); /* ensure all map flushes are postponed */ - - if (portal && !In_endgame(&u.uz)) { - /* find the portal on the new level */ - register struct trap *ttrap; - - for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap) - if (ttrap->ttyp == MAGIC_PORTAL) break; - - if (!ttrap) panic("goto_level: no corresponding portal!"); - seetrap(ttrap); - u_on_newpos(ttrap->tx, ttrap->ty); - } else if (at_stairs && !In_endgame(&u.uz)) { - if (up) { - if (at_ladder) - u_on_newpos(xdnladder, ydnladder); - else if (newdungeon) - u_on_sstairs(1); - else - u_on_dnstairs(); - /* you climb up the {stairs|ladder}; - fly up the stairs; fly up along the ladder */ - pline("%s %s up%s the %s.", - (Punished && !Levitation) ? "With great effort you" : - "You", - Flying ? "fly" : "climb", - (Flying && at_ladder) ? " along" : "", - at_ladder ? "ladder" : "stairs"); - } else { /* down */ - if (at_ladder) - u_on_newpos(xupladder, yupladder); - else if (newdungeon) - u_on_sstairs(0); - else - u_on_upstairs(); - if (!u.dz) { - ; /* stayed on same level? (no transit effects) */ - } else if (Flying) { - if (flags.verbose) - You("fly down %s.", - at_ladder ? "along the ladder" : "the stairs"); - } else if (near_capacity() > UNENCUMBERED || - Punished || Fumbling) { - You("fall down the %s.", at_ladder ? "ladder" : "stairs"); - if (Punished) { - drag_down(); - if (carried(uball)) { - if (uwep == uball) - setuwep((struct obj *)0); - if (uswapwep == uball) - setuswapwep((struct obj *)0); - if (uquiver == uball) - setuqwep((struct obj *)0); - freeinv(uball); - } - } - /* falling off steed has its own losehp() call */ - if (u.usteed) - dismount_steed(DISMOUNT_FELL); - else - losehp(Maybe_Half_Phys(rnd(3)), - at_ladder ? "falling off a ladder" : - "tumbling down a flight of stairs", - KILLED_BY); - selftouch("Falling, you"); - } else { /* ordinary descent */ - if (flags.verbose) - You("%s.", at_ladder ? "climb down the ladder" : - "descend the stairs"); - } - } - } else { /* trap door or level_tele or In_endgame */ - u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0)); - if (falling) { - if (Punished) ballfall(); - selftouch("Falling, you"); - } - } - - if (Punished) placebc(); - obj_delivery(FALSE); - losedogs(); - kill_genocided_monsters(); /* for those wiped out while in limbo */ - /* - * Expire all timers that have gone off while away. Must be - * after migrating monsters and objects are delivered - * (losedogs and obj_delivery). - */ - run_timers(); - - initrack(); - - if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) { - /* There's a monster at your target destination; it might be one - which accompanied you--see mon_arrive(dogmove.c)--or perhaps - it was already here. Randomly move you to an adjacent spot - or else the monster to any nearby location. Prior to 3.3.0 - the latter was done unconditionally. */ - coord cc; - - if (!rn2(2) && - enexto(&cc, u.ux, u.uy, youmonst.data) && - distu(cc.x, cc.y) <= 2) - u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/ - else - mnexto(mtmp); - - if ((mtmp = m_at(u.ux, u.uy)) != 0) { - /* there was an unconditional impossible("mnearto failed") - here, but it's not impossible and we're prepared to cope - with the situation, so only say something when debugging */ - if (wizard) pline("(monster in hero's way)"); - if (!rloc(mtmp, TRUE)) - /* no room to move it; send it away, to return later */ - migrate_to_level(mtmp, ledger_no(&u.uz), - MIGR_RANDOM, (coord *)0); - } - } - - /* initial movement of bubbles just before vision_recalc */ - if (Is_waterlevel(&u.uz)) - movebubbles(); - - if (level_info[new_ledger].flags & FORGOTTEN) { - forget_map(ALL_MAP); /* forget the map */ - forget_traps(); /* forget all traps too */ - familiar = TRUE; - level_info[new_ledger].flags &= ~FORGOTTEN; - } - - /* Reset the screen. */ - vision_reset(); /* reset the blockages */ - docrt(); /* does a full vision recalc */ - flush_screen(-1); - - /* - * Move all plines beyond the screen reset. - */ - - /* special levels can have a custom arrival message */ - deliver_splev_message(); - - /* give room entrance message, if any */ - check_special_room(FALSE); - - /* deliver objects traveling with player */ - obj_delivery(TRUE); - - /* Check whether we just entered Gehennom. */ - if (!In_hell(&u.uz0) && Inhell) { - if (Is_valley(&u.uz)) { - You("arrive at the Valley of the Dead..."); - pline_The("odor of burnt flesh and decay pervades the air."); + /* record this level transition as a potential seen branch unless using + * some non-standard means of transportation (level teleport). + */ + if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum)) + recbranch_mapseen(&u.uz, newlevel); + assign_level(&u.uz0, &u.uz); + assign_level(&u.uz, newlevel); + assign_level(&u.utolev, newlevel); + u.utotype = 0; + if (dunlev_reached(&u.uz) < dunlev(&u.uz)) + dunlev_reached(&u.uz) = dunlev(&u.uz); + reset_rndmonst(NON_PM); /* u.uz change affects monster generation */ + + /* set default level change destination areas */ + /* the special level code may override these */ + (void) memset((genericptr_t) &updest, 0, sizeof updest); + (void) memset((genericptr_t) &dndest, 0, sizeof dndest); + + if (!(level_info[new_ledger].flags & LFILE_EXISTS)) { + /* entering this level for first time; make it now */ + if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) { + impossible("goto_level: returning to discarded level?"); + level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED); + } + mklev(); + new = TRUE; /* made the level */ + } else { + /* returning to previously visited level; reload it */ + fd = open_levelfile(new_ledger, whynot); + if (fd < 0) { + pline1(whynot); + pline("Probably someone removed it."); + Strcpy(killer.name, whynot); + done(TRICKED); + /* we'll reach here if running in wizard mode */ + error("Cannot continue this game."); + } + minit(); /* ZEROCOMP */ + getlev(fd, hackpid, new_ledger, FALSE); + (void) close(fd); + oinit(); /* reassign level dependent obj probabilities */ + } + /* do this prior to level-change pline messages */ + vision_reset(); /* clear old level's line-of-sight */ + vision_full_recalc = 0; /* don't let that reenable vision yet */ + flush_screen(-1); /* ensure all map flushes are postponed */ + + if (portal && !In_endgame(&u.uz)) { + /* find the portal on the new level */ + register struct trap *ttrap; + + for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap) + if (ttrap->ttyp == MAGIC_PORTAL) break; + + if (!ttrap) panic("goto_level: no corresponding portal!"); + seetrap(ttrap); + u_on_newpos(ttrap->tx, ttrap->ty); + } else if (at_stairs && !In_endgame(&u.uz)) { + if (up) { + if (at_ladder) + u_on_newpos(xdnladder, ydnladder); + else if (newdungeon) + u_on_sstairs(1); + else + u_on_dnstairs(); + /* you climb up the {stairs|ladder}; + fly up the stairs; fly up along the ladder */ + pline("%s %s up%s the %s.", + (Punished && !Levitation) ? "With great effort you" : + "You", + Flying ? "fly" : "climb", + (Flying && at_ladder) ? " along" : "", + at_ladder ? "ladder" : "stairs"); + } else { /* down */ + if (at_ladder) + u_on_newpos(xupladder, yupladder); + else if (newdungeon) + u_on_sstairs(0); + else + u_on_upstairs(); + if (!u.dz) { + ; /* stayed on same level? (no transit effects) */ + } else if (Flying) { + if (flags.verbose) + You("fly down %s.", + at_ladder ? "along the ladder" : "the stairs"); + } else if (near_capacity() > UNENCUMBERED || + Punished || Fumbling) { + You("fall down the %s.", at_ladder ? "ladder" : "stairs"); + if (Punished) { + drag_down(); + if (carried(uball)) { + if (uwep == uball) + setuwep((struct obj *)0); + if (uswapwep == uball) + setuswapwep((struct obj *)0); + if (uquiver == uball) + setuqwep((struct obj *)0); + freeinv(uball); + } + } + /* falling off steed has its own losehp() call */ + if (u.usteed) + dismount_steed(DISMOUNT_FELL); + else + losehp(Maybe_Half_Phys(rnd(3)), + at_ladder ? "falling off a ladder" : + "tumbling down a flight of stairs", + KILLED_BY); + selftouch("Falling, you"); + } else { /* ordinary descent */ + if (flags.verbose) + You("%s.", at_ladder ? "climb down the ladder" : + "descend the stairs"); + } + } + } else { /* trap door or level_tele or In_endgame */ + u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0)); + if (falling) { + if (Punished) ballfall(); + selftouch("Falling, you"); + } + } + + if (Punished) placebc(); + obj_delivery(FALSE); + losedogs(); + kill_genocided_monsters(); /* for those wiped out while in limbo */ + /* + * Expire all timers that have gone off while away. Must be + * after migrating monsters and objects are delivered + * (losedogs and obj_delivery). + */ + run_timers(); + + initrack(); + + if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) { + /* There's a monster at your target destination; it might be one + which accompanied you--see mon_arrive(dogmove.c)--or perhaps + it was already here. Randomly move you to an adjacent spot + or else the monster to any nearby location. Prior to 3.3.0 + the latter was done unconditionally. */ + coord cc; + + if (!rn2(2) && + enexto(&cc, u.ux, u.uy, youmonst.data) && + distu(cc.x, cc.y) <= 2) + u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/ + else + mnexto(mtmp); + + if ((mtmp = m_at(u.ux, u.uy)) != 0) { + /* there was an unconditional impossible("mnearto failed") + here, but it's not impossible and we're prepared to cope + with the situation, so only say something when debugging */ + if (wizard) pline("(monster in hero's way)"); + if (!rloc(mtmp, TRUE)) + /* no room to move it; send it away, to return later */ + migrate_to_level(mtmp, ledger_no(&u.uz), + MIGR_RANDOM, (coord *)0); + } + } + + /* initial movement of bubbles just before vision_recalc */ + if (Is_waterlevel(&u.uz)) + movebubbles(); + + if (level_info[new_ledger].flags & FORGOTTEN) { + forget_map(ALL_MAP); /* forget the map */ + forget_traps(); /* forget all traps too */ + familiar = TRUE; + level_info[new_ledger].flags &= ~FORGOTTEN; + } + + /* Reset the screen. */ + vision_reset(); /* reset the blockages */ + docrt(); /* does a full vision recalc */ + flush_screen(-1); + + /* + * Move all plines beyond the screen reset. + */ + + /* special levels can have a custom arrival message */ + deliver_splev_message(); + + /* give room entrance message, if any */ + check_special_room(FALSE); + + /* deliver objects traveling with player */ + obj_delivery(TRUE); + + /* Check whether we just entered Gehennom. */ + if (!In_hell(&u.uz0) && Inhell) { + if (Is_valley(&u.uz)) { + You("arrive at the Valley of the Dead..."); + pline_The("odor of burnt flesh and decay pervades the air."); #ifdef MICRO - display_nhwindow(WIN_MESSAGE, FALSE); + display_nhwindow(WIN_MESSAGE, FALSE); #endif - You_hear("groans and moans everywhere."); - } else pline("It is hot here. You smell smoke..."); - } - /* in case we've managed to bypass the Valley's stairway down */ - if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1; - - if (familiar) { - static const char * const fam_msgs[4] = { - "You have a sense of deja vu.", - "You feel like you've been here before.", - "This place %s familiar...", - 0 /* no message */ - }; - static const char * const halu_fam_msgs[4] = { - "Whoa! Everything %s different.", - "You are surrounded by twisty little passages, all alike.", - "Gee, this %s like uncle Conan's place...", - 0 /* no message */ - }; - const char *mesg; - char buf[BUFSZ]; - int which = rn2(4); - - if (Hallucination) - mesg = halu_fam_msgs[which]; - else - mesg = fam_msgs[which]; - if (mesg && index(mesg, '%')) { - Sprintf(buf, mesg, !Blind ? "looks" : "seems"); - mesg = buf; - } - if (mesg) pline1(mesg); - } - - /* special location arrival messages/events */ - if (In_endgame(&u.uz)) { - if (new && on_level(&u.uz, &astral_level)) - final_level(); /* guardian angel,&c */ - else if (newdungeon && u.uhave.amulet) - resurrect(); /* force confrontation with Wizard */ - } else if (In_quest(&u.uz)) { - onquest(); /* might be reaching locate|goal level */ - } else if (In_V_tower(&u.uz)) { - if (newdungeon && In_hell(&u.uz0)) - pline_The("heat and smoke are gone."); - } else if (Is_knox(&u.uz)) { - /* alarm stops working once Croesus has died */ - if (new || !mvitals[PM_CROESUS].died) { - You("have penetrated a high security area!"); - pline("An alarm sounds!"); - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - mtmp->msleeping = 0; - } - } - } else { - if (new && Is_rogue_level(&u.uz)) - You("enter what seems to be an older, more primitive world."); - /* main dungeon message from your quest leader */ - if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && - !(u.uevent.qcompleted || u.uevent.qexpelled || - quest_status.leader_is_dead)) { - if (!u.uevent.qcalled) { - u.uevent.qcalled = 1; - com_pager(2); /* main "leader needs help" message */ - } else { /* reminder message */ - com_pager(Role_if(PM_ROGUE) ? 4 : 3); - } - } - } - - assign_level(&u.uz0, &u.uz); /* reset u.uz0 */ + You_hear("groans and moans everywhere."); + } else pline("It is hot here. You smell smoke..."); + } + /* in case we've managed to bypass the Valley's stairway down */ + if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1; + + if (familiar) { + static const char * const fam_msgs[4] = { + "You have a sense of deja vu.", + "You feel like you've been here before.", + "This place %s familiar...", + 0 /* no message */ + }; + static const char * const halu_fam_msgs[4] = { + "Whoa! Everything %s different.", + "You are surrounded by twisty little passages, all alike.", + "Gee, this %s like uncle Conan's place...", + 0 /* no message */ + }; + const char *mesg; + char buf[BUFSZ]; + int which = rn2(4); + + if (Hallucination) + mesg = halu_fam_msgs[which]; + else + mesg = fam_msgs[which]; + if (mesg && index(mesg, '%')) { + Sprintf(buf, mesg, !Blind ? "looks" : "seems"); + mesg = buf; + } + if (mesg) pline1(mesg); + } + + /* special location arrival messages/events */ + if (In_endgame(&u.uz)) { + if (new && on_level(&u.uz, &astral_level)) + final_level(); /* guardian angel,&c */ + else if (newdungeon && u.uhave.amulet) + resurrect(); /* force confrontation with Wizard */ + } else if (In_quest(&u.uz)) { + onquest(); /* might be reaching locate|goal level */ + } else if (In_V_tower(&u.uz)) { + if (newdungeon && In_hell(&u.uz0)) + pline_The("heat and smoke are gone."); + } else if (Is_knox(&u.uz)) { + /* alarm stops working once Croesus has died */ + if (new || !mvitals[PM_CROESUS].died) { + You("have penetrated a high security area!"); + pline("An alarm sounds!"); + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + mtmp->msleeping = 0; + } + } + } else { + if (new && Is_rogue_level(&u.uz)) + You("enter what seems to be an older, more primitive world."); + /* main dungeon message from your quest leader */ + if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && + !(u.uevent.qcompleted || u.uevent.qexpelled || + quest_status.leader_is_dead)) { + if (!u.uevent.qcalled) { + u.uevent.qcalled = 1; + com_pager(2); /* main "leader needs help" message */ + } else { /* reminder message */ + com_pager(Role_if(PM_ROGUE) ? 4 : 3); + } + } + } + + assign_level(&u.uz0, &u.uz); /* reset u.uz0 */ #ifdef INSURANCE - save_currentstate(); + save_currentstate(); #endif - /* assume this will always return TRUE when changing level */ - (void) in_out_region(u.ux, u.uy); - (void) pickup(1); + /* assume this will always return TRUE when changing level */ + (void) in_out_region(u.ux, u.uy); + (void) pickup(1); } STATIC_OVL void final_level() { - struct monst *mtmp; + struct monst *mtmp; - /* reset monster hostility relative to player */ - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - reset_hostility(mtmp); - } + /* reset monster hostility relative to player */ + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + reset_hostility(mtmp); + } - /* create some player-monsters */ - create_mplayers(rn1(4, 3), TRUE); + /* create some player-monsters */ + create_mplayers(rn1(4, 3), TRUE); - /* create a guardian angel next to player, if worthy */ - gain_guardian_angel(); + /* create a guardian angel next to player, if worthy */ + gain_guardian_angel(); } static char *dfr_pre_msg = 0, /* pline() before level change */ - *dfr_post_msg = 0; /* pline() after level change */ + *dfr_post_msg = 0; /* pline() after level change */ /* change levels at the end of this turn, after monsters finish moving */ void @@ -1424,49 +1432,49 @@ boolean at_stairs, falling; int portal_flag; const char *pre_msg, *post_msg; { - int typmask = 0100; /* non-zero triggers `deferred_goto' */ - - /* destination flags (`goto_level' args) */ - if (at_stairs) typmask |= 1; - if (falling) typmask |= 2; - if (portal_flag) typmask |= 4; - if (portal_flag < 0) typmask |= 0200; /* flag for portal removal */ - u.utotype = typmask; - /* destination level */ - assign_level(&u.utolev, tolev); - - if (pre_msg) - dfr_pre_msg = dupstr(pre_msg); - if (post_msg) - dfr_post_msg = dupstr(post_msg); + int typmask = 0100; /* non-zero triggers `deferred_goto' */ + + /* destination flags (`goto_level' args) */ + if (at_stairs) typmask |= 1; + if (falling) typmask |= 2; + if (portal_flag) typmask |= 4; + if (portal_flag < 0) typmask |= 0200; /* flag for portal removal */ + u.utotype = typmask; + /* destination level */ + assign_level(&u.utolev, tolev); + + if (pre_msg) + dfr_pre_msg = dupstr(pre_msg); + if (post_msg) + dfr_post_msg = dupstr(post_msg); } /* handle something like portal ejection */ void deferred_goto() { - if (!on_level(&u.uz, &u.utolev)) { - d_level dest; - int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */ - - assign_level(&dest, &u.utolev); - if (dfr_pre_msg) pline1(dfr_pre_msg); - goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4)); - if (typmask & 0200) { /* remove portal */ - struct trap *t = t_at(u.ux, u.uy); - - if (t) { - deltrap(t); - newsym(u.ux, u.uy); - } - } - if (dfr_post_msg) pline1(dfr_post_msg); - } - u.utotype = 0; /* our caller keys off of this */ - if (dfr_pre_msg) - free((genericptr_t)dfr_pre_msg), dfr_pre_msg = 0; - if (dfr_post_msg) - free((genericptr_t)dfr_post_msg), dfr_post_msg = 0; + if (!on_level(&u.uz, &u.utolev)) { + d_level dest; + int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */ + + assign_level(&dest, &u.utolev); + if (dfr_pre_msg) pline1(dfr_pre_msg); + goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4)); + if (typmask & 0200) { /* remove portal */ + struct trap *t = t_at(u.ux, u.uy); + + if (t) { + deltrap(t); + newsym(u.ux, u.uy); + } + } + if (dfr_post_msg) pline1(dfr_post_msg); + } + u.utotype = 0; /* our caller keys off of this */ + if (dfr_pre_msg) + free((genericptr_t)dfr_pre_msg), dfr_pre_msg = 0; + if (dfr_post_msg) + free((genericptr_t)dfr_post_msg), dfr_post_msg = 0; } /* @@ -1488,73 +1496,73 @@ struct obj *corpse; is_uwep = (corpse == uwep); chewed = (corpse->oeaten != 0); Strcpy(cname, corpse_xname(corpse, - chewed ? "bite-covered" : (const char *)0, - CXN_SINGULAR)); + chewed ? "bite-covered" : (const char *)0, + CXN_SINGULAR)); mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0; if (where == OBJ_CONTAINED) { - struct monst *mtmp2; + struct monst *mtmp2; - container = corpse->ocontainer; - mtmp2 = get_container_location(container, &container_where, (int *)0); - /* container_where is the outermost container's location even if nested */ - if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2; + container = corpse->ocontainer; + mtmp2 = get_container_location(container, &container_where, (int *)0); + /* container_where is the outermost container's location even if nested */ + if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2; } mtmp = revive(corpse, FALSE); /* corpse is gone if successful */ if (mtmp) { - switch (where) { - case OBJ_INVENT: - if (is_uwep) - pline_The("%s writhes out of your grasp!", cname); - else - You_feel("squirming in your backpack!"); - break; - - case OBJ_FLOOR: - if (cansee(mtmp->mx, mtmp->my)) - pline("%s rises from the dead!", chewed ? - Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); - break; - - case OBJ_MINVENT: /* probably a nymph's */ - if (cansee(mtmp->mx, mtmp->my)) { - if (canseemon(mcarry)) - pline("Startled, %s drops %s as it revives!", - mon_nam(mcarry), an(cname)); - else - pline("%s suddenly appears!", chewed ? - Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); - } - break; - case OBJ_CONTAINED: - { - char sackname[BUFSZ]; - - if (container_where == OBJ_MINVENT && - cansee(mtmp->mx, mtmp->my) && - mcarry && canseemon(mcarry) && container) { - pline("%s writhes out of %s!", - Amonnam(mtmp), yname(container)); - } else if (container_where == OBJ_INVENT && container) { - Strcpy(sackname, an(xname(container))); - pline("%s %s out of %s in your pack!", - Blind ? Something : Amonnam(mtmp), - locomotion(mtmp->data,"writhes"), - sackname); - } else if (container_where == OBJ_FLOOR && container && - cansee(mtmp->mx, mtmp->my)) { - Strcpy(sackname, an(xname(container))); - pline("%s escapes from %s!", Amonnam(mtmp), sackname); - } - break; - } - default: - /* we should be able to handle the other cases... */ - impossible("revive_corpse: lost corpse @ %d", where); - break; - } - return TRUE; + switch (where) { + case OBJ_INVENT: + if (is_uwep) + pline_The("%s writhes out of your grasp!", cname); + else + You_feel("squirming in your backpack!"); + break; + + case OBJ_FLOOR: + if (cansee(mtmp->mx, mtmp->my)) + pline("%s rises from the dead!", chewed ? + Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); + break; + + case OBJ_MINVENT: /* probably a nymph's */ + if (cansee(mtmp->mx, mtmp->my)) { + if (canseemon(mcarry)) + pline("Startled, %s drops %s as it revives!", + mon_nam(mcarry), an(cname)); + else + pline("%s suddenly appears!", chewed ? + Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); + } + break; + case OBJ_CONTAINED: + { + char sackname[BUFSZ]; + + if (container_where == OBJ_MINVENT && + cansee(mtmp->mx, mtmp->my) && + mcarry && canseemon(mcarry) && container) { + pline("%s writhes out of %s!", + Amonnam(mtmp), yname(container)); + } else if (container_where == OBJ_INVENT && container) { + Strcpy(sackname, an(xname(container))); + pline("%s %s out of %s in your pack!", + Blind ? Something : Amonnam(mtmp), + locomotion(mtmp->data,"writhes"), + sackname); + } else if (container_where == OBJ_FLOOR && container && + cansee(mtmp->mx, mtmp->my)) { + Strcpy(sackname, an(xname(container))); + pline("%s escapes from %s!", Amonnam(mtmp), sackname); + } + break; + } + default: + /* we should be able to handle the other cases... */ + impossible("revive_corpse: lost corpse @ %d", where); + break; + } + return TRUE; } return FALSE; } @@ -1574,82 +1582,82 @@ long timeout UNUSED; /* corpse will revive somewhere else if there is a monster in the way; Riders get a chance to try to bump the obstacle out of their way */ if ((mptr->mflags3 & M3_DISPLACES) != 0 && body->where == OBJ_FLOOR && - get_obj_location(body, &x, &y, 0) && (mtmp = m_at(x, y)) != 0) { - boolean notice_it = canseemon(mtmp); /* before rloc() */ - char *monname = Monnam(mtmp); - - if (rloc(mtmp, TRUE)) { - if (notice_it && !canseemon(mtmp)) - pline("%s vanishes.", monname); - else if (!notice_it && canseemon(mtmp)) - pline("%s appears.", Monnam(mtmp)); /* not pre-rloc monname */ - else if (notice_it && dist2(mtmp->mx, mtmp->my, x, y) > 2) - pline("%s teleports.", monname); /* saw it and still see it */ - } + get_obj_location(body, &x, &y, 0) && (mtmp = m_at(x, y)) != 0) { + boolean notice_it = canseemon(mtmp); /* before rloc() */ + char *monname = Monnam(mtmp); + + if (rloc(mtmp, TRUE)) { + if (notice_it && !canseemon(mtmp)) + pline("%s vanishes.", monname); + else if (!notice_it && canseemon(mtmp)) + pline("%s appears.", Monnam(mtmp)); /* not pre-rloc monname */ + else if (notice_it && dist2(mtmp->mx, mtmp->my, x, y) > 2) + pline("%s teleports.", monname); /* saw it and still see it */ + } } /* if we succeed, the corpse is gone */ if (!revive_corpse(body)) { - long when; - int action; - - if (is_rider(mptr) && rn2(99)) { /* Rider usually tries again */ - action = REVIVE_MON; - for (when = 3L; when < 67L; when++) - if (!rn2(3)) break; - } else { /* rot this corpse away */ - You_feel("%sless hassled.", is_rider(mptr) ? "much " : ""); - action = ROT_CORPSE; - when = 250L - (monstermoves - body->age); - if (when < 1L) when = 1L; - } - (void) start_timer(when, TIMER_OBJECT, action, arg); + long when; + int action; + + if (is_rider(mptr) && rn2(99)) { /* Rider usually tries again */ + action = REVIVE_MON; + for (when = 3L; when < 67L; when++) + if (!rn2(3)) break; + } else { /* rot this corpse away */ + You_feel("%sless hassled.", is_rider(mptr) ? "much " : ""); + action = ROT_CORPSE; + when = 250L - (monstermoves - body->age); + if (when < 1L) when = 1L; + } + (void) start_timer(when, TIMER_OBJECT, action, arg); } } int donull() { - return(1); /* Do nothing, but let other things happen */ + return(1); /* Do nothing, but let other things happen */ } STATIC_PTR int wipeoff(VOID_ARGS) { - if(u.ucreamed < 4) u.ucreamed = 0; - else u.ucreamed -= 4; - if (Blinded < 4) Blinded = 0; - else Blinded -= 4; - if (!Blinded) { - pline("You've got the glop off."); - u.ucreamed = 0; - if (!gulp_blnd_check()) { - Blinded = 1; - make_blinded(0L,TRUE); - } - return(0); - } else if (!u.ucreamed) { - Your("%s feels clean now.", body_part(FACE)); - return(0); - } - return(1); /* still busy */ + if(u.ucreamed < 4) u.ucreamed = 0; + else u.ucreamed -= 4; + if (Blinded < 4) Blinded = 0; + else Blinded -= 4; + if (!Blinded) { + pline("You've got the glop off."); + u.ucreamed = 0; + if (!gulp_blnd_check()) { + Blinded = 1; + make_blinded(0L,TRUE); + } + return(0); + } else if (!u.ucreamed) { + Your("%s feels clean now.", body_part(FACE)); + return(0); + } + return(1); /* still busy */ } int dowipe() { - if(u.ucreamed) { - static NEARDATA char buf[39]; - - Sprintf(buf, "wiping off your %s", body_part(FACE)); - set_occupation(wipeoff, buf, 0); - /* Not totally correct; what if they change back after now - * but before they're finished wiping? - */ - return(1); - } - Your("%s is already clean.", body_part(FACE)); - return(1); + if(u.ucreamed) { + static NEARDATA char buf[39]; + + Sprintf(buf, "wiping off your %s", body_part(FACE)); + set_occupation(wipeoff, buf, 0); + /* Not totally correct; what if they change back after now + * but before they're finished wiping? + */ + return(1); + } + Your("%s is already clean.", body_part(FACE)); + return(1); } void @@ -1657,57 +1665,57 @@ set_wounded_legs(side, timex) register long side; register int timex; { - /* KMH -- STEED - * If you are riding, your steed gets the wounded legs instead. - * You still call this function, but don't lose hp. - * Caller is also responsible for adjusting messages. - */ - - if(!Wounded_legs) { - ATEMP(A_DEX)--; - context.botl = 1; - } - - if(!Wounded_legs || (HWounded_legs & TIMEOUT)) - HWounded_legs = timex; - EWounded_legs = side; - (void)encumber_msg(); + /* KMH -- STEED + * If you are riding, your steed gets the wounded legs instead. + * You still call this function, but don't lose hp. + * Caller is also responsible for adjusting messages. + */ + + if(!Wounded_legs) { + ATEMP(A_DEX)--; + context.botl = 1; + } + + if(!Wounded_legs || (HWounded_legs & TIMEOUT)) + HWounded_legs = timex; + EWounded_legs = side; + (void)encumber_msg(); } void heal_legs() { - if (Wounded_legs) { - if (ATEMP(A_DEX) < 0) { - ATEMP(A_DEX)++; - context.botl = 1; - } - - if (!u.usteed) - { - const char *legs = body_part(LEG); - - if ((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) - legs = makeplural(legs); - /* this used to say "somewhat better" but that was - misleading since legs are being fully healed */ - Your("%s %s better.", legs, vtense(legs, "feel")); - } - - HWounded_legs = EWounded_legs = 0; - - /* Wounded_legs reduces carrying capacity, so we want - an encumbrance check when they're healed. However, - while dismounting, first steed's legs get healed, - then hero is dropped to floor and a new encumbrance - check is made [in dismount_steed()]. So don't give - encumbrance feedback during the dismount stage - because it could seem to be shown out of order and - it might be immediately contradicted [able to carry - more when steed becomes healthy, then possible floor - feedback, then able to carry less when back on foot]. */ - if (!in_steed_dismounting) (void)encumber_msg(); - } + if (Wounded_legs) { + if (ATEMP(A_DEX) < 0) { + ATEMP(A_DEX)++; + context.botl = 1; + } + + if (!u.usteed) + { + const char *legs = body_part(LEG); + + if ((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) + legs = makeplural(legs); + /* this used to say "somewhat better" but that was + misleading since legs are being fully healed */ + Your("%s %s better.", legs, vtense(legs, "feel")); + } + + HWounded_legs = EWounded_legs = 0; + + /* Wounded_legs reduces carrying capacity, so we want + an encumbrance check when they're healed. However, + while dismounting, first steed's legs get healed, + then hero is dropped to floor and a new encumbrance + check is made [in dismount_steed()]. So don't give + encumbrance feedback during the dismount stage + because it could seem to be shown out of order and + it might be immediately contradicted [able to carry + more when steed becomes healthy, then possible floor + feedback, then able to carry less when back on foot]. */ + if (!in_steed_dismounting) (void)encumber_msg(); + } } /*do.c*/ diff --git a/src/hack.c b/src/hack.c index 1edfb9f4e..12e7c4e2d 100644 --- a/src/hack.c +++ b/src/hack.c @@ -69,26 +69,26 @@ const char *msg; boolean revived = FALSE; for(otmp = level.objects[x][y]; otmp; otmp = otmp2) { - otmp2 = otmp->nexthere; - if (otmp->otyp == CORPSE && - (is_rider(&mons[otmp->corpsenm]) || - otmp->corpsenm == PM_WIZARD_OF_YENDOR)) { - /* move any living monster already at that location */ - if((mtmp = m_at(x,y)) && enexto(&cc, x, y, mtmp->data)) - rloc_to(mtmp, cc.x, cc.y); - if(msg) Norep("%s", msg); - revived = revive_corpse(otmp); - } + otmp2 = otmp->nexthere; + if (otmp->otyp == CORPSE && + (is_rider(&mons[otmp->corpsenm]) || + otmp->corpsenm == PM_WIZARD_OF_YENDOR)) { + /* move any living monster already at that location */ + if((mtmp = m_at(x,y)) && enexto(&cc, x, y, mtmp->data)) + rloc_to(mtmp, cc.x, cc.y); + if(msg) Norep("%s", msg); + revived = revive_corpse(otmp); + } } /* this location might not be safe, if not, move revived monster */ if (revived) { - mtmp = m_at(x,y); - if (mtmp && !goodpos(x, y, mtmp, 0) && - enexto(&cc, x, y, mtmp->data)) { - rloc_to(mtmp, cc.x, cc.y); - } - /* else impossible? */ + mtmp = m_at(x,y); + if (mtmp && !goodpos(x, y, mtmp, 0) && + enexto(&cc, x, y, mtmp->data)) { + rloc_to(mtmp, cc.x, cc.y); + } + /* else impossible? */ } return (revived); @@ -104,226 +104,226 @@ moverock() sx = u.ux + u.dx, sy = u.uy + u.dy; /* boulder starting position */ while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { - /* make sure that this boulder is visible as the top object */ - if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy); - - rx = u.ux + 2 * u.dx; /* boulder destination position */ - ry = u.uy + 2 * u.dy; - nomul(0); - if (Levitation || Is_airlevel(&u.uz)) { - if (Blind) feel_location(sx, sy); - You("don't have enough leverage to push %s.", the(xname(otmp))); - /* Give them a chance to climb over it? */ - return -1; - } - if (verysmall(youmonst.data) && !u.usteed) { - if (Blind) feel_location(sx, sy); - pline("You're too small to push that %s.", xname(otmp)); - goto cannot_push; - } - if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) && - levl[rx][ry].typ != IRONBARS && - (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || - doorless_door(rx, ry)) && - !sobj_at(BOULDER, rx, ry)) { - ttmp = t_at(rx, ry); - mtmp = m_at(rx, ry); - - /* KMH -- Sokoban doesn't let you push boulders diagonally */ - if (Sokoban && u.dx && u.dy) { - if (Blind) feel_location(sx,sy); - pline("%s won't roll diagonally on this %s.", - The(xname(otmp)), surface(sx, sy)); - goto cannot_push; - } - - if (revive_nasty(rx, ry, "You sense movement on the other side.")) - return (-1); - - if (mtmp && !noncorporeal(mtmp->data) && - (!mtmp->mtrapped || - !(ttmp && ((ttmp->ttyp == PIT) || - (ttmp->ttyp == SPIKED_PIT))))) { - if (Blind) feel_location(sx, sy); - if (canspotmon(mtmp)) - pline("There's %s on the other side.", a_monnam(mtmp)); - else { - You_hear("a monster behind %s.", the(xname(otmp))); - map_invisible(rx, ry); - } - if (flags.verbose) - pline("Perhaps that's why %s cannot move it.", - u.usteed ? y_monnam(u.usteed) : "you"); - goto cannot_push; - } - - if (ttmp) { - /* if a trap operates on the boulder, don't attempt - to move any others at this location; return -1 - if another boulder is in hero's way, or 0 if he - should advance to the vacated boulder position */ - switch(ttmp->ttyp) { - case LANDMINE: - if (rn2(10)) { - obj_extract_self(otmp); - place_object(otmp, rx, ry); - newsym(sx, sy); - pline("KAABLAMM!!! %s %s land mine.", - Tobjnam(otmp, "trigger"), - ttmp->madeby_u ? "your" : "a"); - blow_up_landmine(ttmp); - /* if the boulder remains, it should fill the pit */ - fill_pit(u.ux, u.uy); - if (cansee(rx,ry)) newsym(rx,ry); - return sobj_at(BOULDER, sx, sy) ? -1 : 0; - } - break; - case SPIKED_PIT: - case PIT: - obj_extract_self(otmp); - /* vision kludge to get messages right; - the pit will temporarily be seen even - if this is one among multiple boulders */ - if (!Blind) viz_array[ry][rx] |= IN_SIGHT; - if (!flooreffects(otmp, rx, ry, "fall")) { - place_object(otmp, rx, ry); - } - if (mtmp && !Blind) newsym(rx, ry); - return sobj_at(BOULDER, sx, sy) ? -1 : 0; - case HOLE: - case TRAPDOOR: - if (Blind) - pline("Kerplunk! You no longer feel %s.", - the(xname(otmp))); - else - pline("%s%s and %s a %s in the %s!", - Tobjnam(otmp, - (ttmp->ttyp == TRAPDOOR) ? "trigger" : "fall"), - (ttmp->ttyp == TRAPDOOR) ? "" : " into", - otense(otmp, "plug"), - (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole", - surface(rx, ry)); - deltrap(ttmp); - delobj(otmp); - bury_objs(rx, ry); - levl[rx][ry].wall_info &= ~W_NONDIGGABLE; - levl[rx][ry].candig = 1; - if (cansee(rx,ry)) newsym(rx,ry); - return sobj_at(BOULDER, sx, sy) ? -1 : 0; - case LEVEL_TELEP: - case TELEP_TRAP: - { - int newlev = 0; /* lint suppression */ - d_level dest; - - if (ttmp->ttyp == LEVEL_TELEP) { - newlev = random_teleport_level(); - if (newlev == depth(&u.uz) || In_endgame(&u.uz)) - /* trap didn't work; skip "disappears" message */ - goto dopush; - } - if (u.usteed) + /* make sure that this boulder is visible as the top object */ + if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy); + + rx = u.ux + 2 * u.dx; /* boulder destination position */ + ry = u.uy + 2 * u.dy; + nomul(0); + if (Levitation || Is_airlevel(&u.uz)) { + if (Blind) feel_location(sx, sy); + You("don't have enough leverage to push %s.", the(xname(otmp))); + /* Give them a chance to climb over it? */ + return -1; + } + if (verysmall(youmonst.data) && !u.usteed) { + if (Blind) feel_location(sx, sy); + pline("You're too small to push that %s.", xname(otmp)); + goto cannot_push; + } + if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) && + levl[rx][ry].typ != IRONBARS && + (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || + doorless_door(rx, ry)) && + !sobj_at(BOULDER, rx, ry)) { + ttmp = t_at(rx, ry); + mtmp = m_at(rx, ry); + + /* KMH -- Sokoban doesn't let you push boulders diagonally */ + if (Sokoban && u.dx && u.dy) { + if (Blind) feel_location(sx,sy); + pline("%s won't roll diagonally on this %s.", + The(xname(otmp)), surface(sx, sy)); + goto cannot_push; + } + + if (revive_nasty(rx, ry, "You sense movement on the other side.")) + return (-1); + + if (mtmp && !noncorporeal(mtmp->data) && + (!mtmp->mtrapped || + !(ttmp && ((ttmp->ttyp == PIT) || + (ttmp->ttyp == SPIKED_PIT))))) { + if (Blind) feel_location(sx, sy); + if (canspotmon(mtmp)) + pline("There's %s on the other side.", a_monnam(mtmp)); + else { + You_hear("a monster behind %s.", the(xname(otmp))); + map_invisible(rx, ry); + } + if (flags.verbose) + pline("Perhaps that's why %s cannot move it.", + u.usteed ? y_monnam(u.usteed) : "you"); + goto cannot_push; + } + + if (ttmp) { + /* if a trap operates on the boulder, don't attempt + to move any others at this location; return -1 + if another boulder is in hero's way, or 0 if he + should advance to the vacated boulder position */ + switch(ttmp->ttyp) { + case LANDMINE: + if (rn2(10)) { + obj_extract_self(otmp); + place_object(otmp, rx, ry); + newsym(sx, sy); + pline("KAABLAMM!!! %s %s land mine.", + Tobjnam(otmp, "trigger"), + ttmp->madeby_u ? "your" : "a"); + blow_up_landmine(ttmp); + /* if the boulder remains, it should fill the pit */ + fill_pit(u.ux, u.uy); + if (cansee(rx,ry)) newsym(rx,ry); + return sobj_at(BOULDER, sx, sy) ? -1 : 0; + } + break; + case SPIKED_PIT: + case PIT: + obj_extract_self(otmp); + /* vision kludge to get messages right; + the pit will temporarily be seen even + if this is one among multiple boulders */ + if (!Blind) viz_array[ry][rx] |= IN_SIGHT; + if (!flooreffects(otmp, rx, ry, "fall")) { + place_object(otmp, rx, ry); + } + if (mtmp && !Blind) newsym(rx, ry); + return sobj_at(BOULDER, sx, sy) ? -1 : 0; + case HOLE: + case TRAPDOOR: + if (Blind) + pline("Kerplunk! You no longer feel %s.", + the(xname(otmp))); + else + pline("%s%s and %s a %s in the %s!", + Tobjnam(otmp, + (ttmp->ttyp == TRAPDOOR) ? "trigger" : "fall"), + (ttmp->ttyp == TRAPDOOR) ? "" : " into", + otense(otmp, "plug"), + (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole", + surface(rx, ry)); + deltrap(ttmp); + delobj(otmp); + bury_objs(rx, ry); + levl[rx][ry].wall_info &= ~W_NONDIGGABLE; + levl[rx][ry].candig = 1; + if (cansee(rx,ry)) newsym(rx,ry); + return sobj_at(BOULDER, sx, sy) ? -1 : 0; + case LEVEL_TELEP: + case TELEP_TRAP: + { + int newlev = 0; /* lint suppression */ + d_level dest; + + if (ttmp->ttyp == LEVEL_TELEP) { + newlev = random_teleport_level(); + if (newlev == depth(&u.uz) || In_endgame(&u.uz)) + /* trap didn't work; skip "disappears" message */ + goto dopush; + } + if (u.usteed) pline("%s pushes %s and suddenly it disappears!", - upstart(y_monnam(u.usteed)), the(xname(otmp))); - else + upstart(y_monnam(u.usteed)), the(xname(otmp))); + else You("push %s and suddenly it disappears!", - the(xname(otmp))); - if (ttmp->ttyp == TELEP_TRAP) { - (void)rloco(otmp); - } else { - obj_extract_self(otmp); - add_to_migration(otmp); - get_level(&dest, newlev); - otmp->ox = dest.dnum; - otmp->oy = dest.dlevel; - otmp->owornmask = (long)MIGR_RANDOM; - } - seetrap(ttmp); - return sobj_at(BOULDER, sx, sy) ? -1 : 0; - } - default: - break; /* boulder not affected by this trap */ - } - } - - if (closed_door(rx, ry)) - goto nopushmsg; - if (boulder_hits_pool(otmp, rx, ry, TRUE)) - continue; - /* - * Re-link at top of fobj chain so that pile order is preserved - * when level is restored. - */ - if (otmp != fobj) { - remove_object(otmp); - place_object(otmp, otmp->ox, otmp->oy); - } - - { + the(xname(otmp))); + if (ttmp->ttyp == TELEP_TRAP) { + (void)rloco(otmp); + } else { + obj_extract_self(otmp); + add_to_migration(otmp); + get_level(&dest, newlev); + otmp->ox = dest.dnum; + otmp->oy = dest.dlevel; + otmp->owornmask = (long)MIGR_RANDOM; + } + seetrap(ttmp); + return sobj_at(BOULDER, sx, sy) ? -1 : 0; + } + default: + break; /* boulder not affected by this trap */ + } + } + + if (closed_door(rx, ry)) + goto nopushmsg; + if (boulder_hits_pool(otmp, rx, ry, TRUE)) + continue; + /* + * Re-link at top of fobj chain so that pile order is preserved + * when level is restored. + */ + if (otmp != fobj) { + remove_object(otmp); + place_object(otmp, otmp->ox, otmp->oy); + } + + { #ifdef LINT /* static long lastmovetime; */ - long lastmovetime; - lastmovetime = 0; + long lastmovetime; + lastmovetime = 0; #else - /* note: reset to zero after save/restore cycle */ - static NEARDATA long lastmovetime; + /* note: reset to zero after save/restore cycle */ + static NEARDATA long lastmovetime; #endif dopush: - if (!u.usteed) { - if (moves > lastmovetime+2 || moves < lastmovetime) - pline("With %s effort you move %s.", - throws_rocks(youmonst.data) ? "little" : "great", - the(xname(otmp))); - exercise(A_STR, TRUE); - } else - pline("%s moves %s.", - upstart(y_monnam(u.usteed)), the(xname(otmp))); - lastmovetime = moves; - } - - /* Move the boulder *after* the message. */ - if (glyph_is_invisible(levl[rx][ry].glyph)) - unmap_object(rx, ry); - movobj(otmp, rx, ry); /* does newsym(rx,ry) */ - if (Blind) { - feel_location(rx,ry); - feel_location(sx, sy); - } else { - newsym(sx, sy); - } - } else { + if (!u.usteed) { + if (moves > lastmovetime+2 || moves < lastmovetime) + pline("With %s effort you move %s.", + throws_rocks(youmonst.data) ? "little" : "great", + the(xname(otmp))); + exercise(A_STR, TRUE); + } else + pline("%s moves %s.", + upstart(y_monnam(u.usteed)), the(xname(otmp))); + lastmovetime = moves; + } + + /* Move the boulder *after* the message. */ + if (glyph_is_invisible(levl[rx][ry].glyph)) + unmap_object(rx, ry); + movobj(otmp, rx, ry); /* does newsym(rx,ry) */ + if (Blind) { + feel_location(rx,ry); + feel_location(sx, sy); + } else { + newsym(sx, sy); + } + } else { nopushmsg: - if (u.usteed) - pline("%s tries to move %s, but cannot.", - upstart(y_monnam(u.usteed)), the(xname(otmp))); - else - You("try to move %s, but in vain.", the(xname(otmp))); - if (Blind) feel_location(sx, sy); + if (u.usteed) + pline("%s tries to move %s, but cannot.", + upstart(y_monnam(u.usteed)), the(xname(otmp))); + else + You("try to move %s, but in vain.", the(xname(otmp))); + if (Blind) feel_location(sx, sy); cannot_push: - if (throws_rocks(youmonst.data)) { - if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { - You("aren't skilled enough to %s %s from %s.", - (flags.pickup && !Sokoban) ? "pick up" : "push aside", - the(xname(otmp)), y_monnam(u.usteed)); - } else { - pline("However, you can easily %s.", - (flags.pickup && !Sokoban) ? - "pick it up" : "push it aside"); - sokoban_guilt(); - break; - } - break; - } - - if (!u.usteed && (((!invent || inv_weight() <= -850) && - (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ) - && IS_ROCK(levl[sx][u.uy].typ)))) - || verysmall(youmonst.data))) { - pline("However, you can squeeze yourself into a small opening."); - sokoban_guilt(); - break; - } else - return (-1); - } + if (throws_rocks(youmonst.data)) { + if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { + You("aren't skilled enough to %s %s from %s.", + (flags.pickup && !Sokoban) ? "pick up" : "push aside", + the(xname(otmp)), y_monnam(u.usteed)); + } else { + pline("However, you can easily %s.", + (flags.pickup && !Sokoban) ? + "pick it up" : "push it aside"); + sokoban_guilt(); + break; + } + break; + } + + if (!u.usteed && (((!invent || inv_weight() <= -850) && + (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ) + && IS_ROCK(levl[sx][u.uy].typ)))) + || verysmall(youmonst.data))) { + pline("However, you can squeeze yourself into a small opening."); + sokoban_guilt(); + break; + } else + return (-1); + } } return (0); } @@ -343,40 +343,40 @@ still_chewing(x,y) const char *digtxt = (char *)0, *dmgtxt = (char *)0; if (context.digging.down) /* not continuing previous dig (w/ pick-axe) */ - (void) memset((genericptr_t)&context.digging, 0, sizeof(struct dig_info)); + (void) memset((genericptr_t)&context.digging, 0, sizeof(struct dig_info)); if (!boulder && IS_ROCK(lev->typ) && !may_dig(x,y)) { - You("hurt your teeth on the %s.", - IS_TREE(lev->typ) ? "tree" : "hard stone"); - nomul(0); - return 1; + You("hurt your teeth on the %s.", + IS_TREE(lev->typ) ? "tree" : "hard stone"); + nomul(0); + return 1; } else if (context.digging.pos.x != x || context.digging.pos.y != y || - !on_level(&context.digging.level, &u.uz)) { - context.digging.down = FALSE; - context.digging.chew = TRUE; - context.digging.warned = FALSE; - context.digging.pos.x = x; - context.digging.pos.y = y; - assign_level(&context.digging.level, &u.uz); - /* solid rock takes more work & time to dig through */ - context.digging.effort = - (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc; - You("start chewing %s %s.", - (boulder || IS_TREE(lev->typ)) ? "on a" : "a hole in the", - boulder ? "boulder" : - IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door"); - watch_dig((struct monst *)0, x, y, FALSE); - return 1; + !on_level(&context.digging.level, &u.uz)) { + context.digging.down = FALSE; + context.digging.chew = TRUE; + context.digging.warned = FALSE; + context.digging.pos.x = x; + context.digging.pos.y = y; + assign_level(&context.digging.level, &u.uz); + /* solid rock takes more work & time to dig through */ + context.digging.effort = + (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc; + You("start chewing %s %s.", + (boulder || IS_TREE(lev->typ)) ? "on a" : "a hole in the", + boulder ? "boulder" : + IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door"); + watch_dig((struct monst *)0, x, y, FALSE); + return 1; } else if ((context.digging.effort += (30 + u.udaminc)) <= 100) { - if (flags.verbose) - You("%s chewing on the %s.", - context.digging.chew ? "continue" : "begin", - boulder ? "boulder" : - IS_TREE(lev->typ) ? "tree" : - IS_ROCK(lev->typ) ? "rock" : "door"); - context.digging.chew = TRUE; - watch_dig((struct monst *)0, x, y, FALSE); - return 1; + if (flags.verbose) + You("%s chewing on the %s.", + context.digging.chew ? "continue" : "begin", + boulder ? "boulder" : + IS_TREE(lev->typ) ? "tree" : + IS_ROCK(lev->typ) ? "rock" : "door"); + context.digging.chew = TRUE; + watch_dig((struct monst *)0, x, y, FALSE); + return 1; } /* Okay, you've chewed through something */ @@ -384,66 +384,66 @@ still_chewing(x,y) u.uhunger += rnd(20); if (boulder) { - delobj(boulder); /* boulder goes bye-bye */ - You("eat the boulder."); /* yum */ - - /* - * The location could still block because of - * 1. More than one boulder - * 2. Boulder stuck in a wall/stone/door. - * - * [perhaps use does_block() below (from vision.c)] - */ - if (IS_ROCK(lev->typ) || closed_door(x,y) || sobj_at(BOULDER,x,y)) { - block_point(x,y); /* delobj will unblock the point */ - /* reset dig state */ - (void) memset((genericptr_t)&context.digging, 0, sizeof(struct dig_info)); - return 1; - } + delobj(boulder); /* boulder goes bye-bye */ + You("eat the boulder."); /* yum */ + + /* + * The location could still block because of + * 1. More than one boulder + * 2. Boulder stuck in a wall/stone/door. + * + * [perhaps use does_block() below (from vision.c)] + */ + if (IS_ROCK(lev->typ) || closed_door(x,y) || sobj_at(BOULDER,x,y)) { + block_point(x,y); /* delobj will unblock the point */ + /* reset dig state */ + (void) memset((genericptr_t)&context.digging, 0, sizeof(struct dig_info)); + return 1; + } } else if (IS_WALL(lev->typ)) { - if (*in_rooms(x, y, SHOPBASE)) { - add_damage(x, y, 10L * ACURRSTR); - dmgtxt = "damage"; - } - digtxt = "chew a hole in the wall."; - if (level.flags.is_maze_lev) { - lev->typ = ROOM; - } else if (level.flags.is_cavernous_lev && !in_town(x, y)) { - lev->typ = CORR; - } else { - lev->typ = DOOR; - lev->doormask = D_NODOOR; - } + if (*in_rooms(x, y, SHOPBASE)) { + add_damage(x, y, 10L * ACURRSTR); + dmgtxt = "damage"; + } + digtxt = "chew a hole in the wall."; + if (level.flags.is_maze_lev) { + lev->typ = ROOM; + } else if (level.flags.is_cavernous_lev && !in_town(x, y)) { + lev->typ = CORR; + } else { + lev->typ = DOOR; + lev->doormask = D_NODOOR; + } } else if (IS_TREE(lev->typ)) { - digtxt = "chew through the tree."; - lev->typ = ROOM; + digtxt = "chew through the tree."; + lev->typ = ROOM; } else if (lev->typ == SDOOR) { - if (lev->doormask & D_TRAPPED) { - lev->doormask = D_NODOOR; - b_trapped("secret door", 0); - } else { - digtxt = "chew through the secret door."; - lev->doormask = D_BROKEN; - } - lev->typ = DOOR; + if (lev->doormask & D_TRAPPED) { + lev->doormask = D_NODOOR; + b_trapped("secret door", 0); + } else { + digtxt = "chew through the secret door."; + lev->doormask = D_BROKEN; + } + lev->typ = DOOR; } else if (IS_DOOR(lev->typ)) { - if (*in_rooms(x, y, SHOPBASE)) { - add_damage(x, y, 400L); - dmgtxt = "break"; - } - if (lev->doormask & D_TRAPPED) { - lev->doormask = D_NODOOR; - b_trapped("door", 0); - } else { - digtxt = "chew through the door."; - lev->doormask = D_BROKEN; - } + if (*in_rooms(x, y, SHOPBASE)) { + add_damage(x, y, 400L); + dmgtxt = "break"; + } + if (lev->doormask & D_TRAPPED) { + lev->doormask = D_NODOOR; + b_trapped("door", 0); + } else { + digtxt = "chew through the door."; + lev->doormask = D_BROKEN; + } } else { /* STONE or SCORR */ - digtxt = "chew a passage through the rock."; - lev->typ = CORR; + digtxt = "chew a passage through the rock."; + lev->typ = CORR; } unblock_point(x, y); /* vision */ @@ -459,11 +459,11 @@ movobj(obj, ox, oy) register struct obj *obj; register xchar ox, oy; { - /* optimize by leaving on the fobj chain? */ - remove_object(obj); - newsym(obj->ox, obj->oy); - place_object(obj, ox, oy); - newsym(ox, oy); + /* optimize by leaving on the fobj chain? */ + remove_object(obj); + newsym(obj->ox, obj->oy); + place_object(obj, ox, oy); + newsym(ox, oy); } static NEARDATA const char fell_on_sink[] = "fell onto a sink"; @@ -471,80 +471,80 @@ static NEARDATA const char fell_on_sink[] = "fell onto a sink"; STATIC_OVL void dosinkfall() { - register struct obj *obj; - int dmg; - boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS), - innate_lev = ((HLevitation & (FROMOUTSIDE|FROMFORM)) != 0L), - ufall = (!innate_lev && !(HFlying || EFlying)); /* BFlying */ - - if (!ufall) { - You(innate_lev ? "wobble unsteadily for a moment." : - "gain control of your flight."); - } else { - long save_ELev = ELevitation, save_HLev = HLevitation; - - /* fake removal of levitation in advance so that final - disclosure will be right in case this turns out to - be fatal; fortunately the fact that rings and boots - are really still worn has no effect on bones data */ - ELevitation = HLevitation = 0L; - You("crash to the floor!"); - dmg = rn1(8, 25 - (int)ACURR(A_CON)); - losehp(Maybe_Half_Phys(dmg), - fell_on_sink, NO_KILLER_PREFIX); - exercise(A_DEX, FALSE); - selftouch("Falling, you"); - for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) - if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) { - You("fell on %s.", doname(obj)); - losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink, NO_KILLER_PREFIX); - exercise(A_CON, FALSE); - } - ELevitation = save_ELev; - HLevitation = save_HLev; - } - - /* - * Interrupt multi-turn putting on/taking off of armor (in which - * case we reached the sink due to being teleported while busy; - * in 3.4.3, Boots_on()/Boots_off() [called via (*aftermv)() when - * 'multi' reaches 0] triggered a crash if we were donning/doffing - * levitation boots [because the Boots_off() below causes 'uarmf' - * to be null by the time 'aftermv' gets called]). - * - * Interrupt donning/doffing if we fall onto the sink, or if the - * code below is going to remove levitation boots even when we - * haven't fallen (innate floating or flying becoming unblocked). - */ - if (ufall || lev_boots) { - (void) stop_donning(lev_boots ? uarmf : (struct obj *)0); - /* recalculate in case uarmf just got set to null */ - lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS); - } - - /* remove worn levitation items */ - ELevitation &= ~W_ARTI; - HLevitation &= ~(I_SPECIAL|TIMEOUT); - HLevitation++; - if(uleft && uleft->otyp == RIN_LEVITATION) { - obj = uleft; - Ring_off(obj); - off_msg(obj); - } - if(uright && uright->otyp == RIN_LEVITATION) { - obj = uright; - Ring_off(obj); - off_msg(obj); - } - if (lev_boots) { - obj = uarmf; - (void)Boots_off(); - off_msg(obj); - } - HLevitation--; - /* probably moot; we're either still levitating or went - through float_down(), but make sure BFlying is up to date */ - float_vs_flight(); + register struct obj *obj; + int dmg; + boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS), + innate_lev = ((HLevitation & (FROMOUTSIDE|FROMFORM)) != 0L), + ufall = (!innate_lev && !(HFlying || EFlying)); /* BFlying */ + + if (!ufall) { + You(innate_lev ? "wobble unsteadily for a moment." : + "gain control of your flight."); + } else { + long save_ELev = ELevitation, save_HLev = HLevitation; + + /* fake removal of levitation in advance so that final + disclosure will be right in case this turns out to + be fatal; fortunately the fact that rings and boots + are really still worn has no effect on bones data */ + ELevitation = HLevitation = 0L; + You("crash to the floor!"); + dmg = rn1(8, 25 - (int)ACURR(A_CON)); + losehp(Maybe_Half_Phys(dmg), + fell_on_sink, NO_KILLER_PREFIX); + exercise(A_DEX, FALSE); + selftouch("Falling, you"); + for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) + if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) { + You("fell on %s.", doname(obj)); + losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink, NO_KILLER_PREFIX); + exercise(A_CON, FALSE); + } + ELevitation = save_ELev; + HLevitation = save_HLev; + } + + /* + * Interrupt multi-turn putting on/taking off of armor (in which + * case we reached the sink due to being teleported while busy; + * in 3.4.3, Boots_on()/Boots_off() [called via (*aftermv)() when + * 'multi' reaches 0] triggered a crash if we were donning/doffing + * levitation boots [because the Boots_off() below causes 'uarmf' + * to be null by the time 'aftermv' gets called]). + * + * Interrupt donning/doffing if we fall onto the sink, or if the + * code below is going to remove levitation boots even when we + * haven't fallen (innate floating or flying becoming unblocked). + */ + if (ufall || lev_boots) { + (void) stop_donning(lev_boots ? uarmf : (struct obj *)0); + /* recalculate in case uarmf just got set to null */ + lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS); + } + + /* remove worn levitation items */ + ELevitation &= ~W_ARTI; + HLevitation &= ~(I_SPECIAL|TIMEOUT); + HLevitation++; + if(uleft && uleft->otyp == RIN_LEVITATION) { + obj = uleft; + Ring_off(obj); + off_msg(obj); + } + if(uright && uright->otyp == RIN_LEVITATION) { + obj = uright; + Ring_off(obj); + off_msg(obj); + } + if (lev_boots) { + obj = uarmf; + (void)Boots_off(); + off_msg(obj); + } + HLevitation--; + /* probably moot; we're either still levitating or went + through float_down(), but make sure BFlying is up to date */ + float_vs_flight(); } boolean @@ -553,7 +553,7 @@ register xchar x,y; /* intended to be called only on ROCKs */ { return (boolean)(!(IS_STWALL(levl[x][y].typ) && - (levl[x][y].wall_info & W_NONDIGGABLE))); + (levl[x][y].wall_info & W_NONDIGGABLE))); } boolean @@ -561,7 +561,7 @@ may_passwall(x,y) register xchar x,y; { return (boolean)(!(IS_STWALL(levl[x][y].typ) && - (levl[x][y].wall_info & W_NONPASSWALL))); + (levl[x][y].wall_info & W_NONPASSWALL))); } boolean @@ -569,10 +569,10 @@ bad_rock(mdat,x,y) struct permonst *mdat; register xchar x,y; { - return((boolean) ((Sokoban && sobj_at(BOULDER,x,y)) || - (IS_ROCK(levl[x][y].typ) - && (!tunnels(mdat) || needspick(mdat) || !may_dig(x,y)) - && !(passes_walls(mdat) && may_passwall(x,y))))); + return((boolean) ((Sokoban && sobj_at(BOULDER,x,y)) || + (IS_ROCK(levl[x][y].typ) + && (!tunnels(mdat) || needspick(mdat) || !may_dig(x,y)) + && !(passes_walls(mdat) && may_passwall(x,y))))); } /* caller has already decided that it's a tight diagonal; check whether a @@ -587,12 +587,12 @@ struct monst *mon; /* too big? */ if (bigmonst(ptr) && - !(amorphous(ptr) || is_whirly(ptr) || - noncorporeal(ptr) || slithy(ptr) || can_fog(mon))) return 1; + !(amorphous(ptr) || is_whirly(ptr) || + noncorporeal(ptr) || slithy(ptr) || can_fog(mon))) return 1; /* lugging too much junk? */ amt = (mon == &youmonst) ? inv_weight() + weight_cap() : - curr_mon_load(mon); + curr_mon_load(mon); if (amt > 600) return 2; /* Sokoban restriction applies to hero only */ @@ -606,7 +606,7 @@ boolean invocation_pos(x, y) xchar x, y; { - return((boolean)(Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y)); + return((boolean)(Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y)); } /* return TRUE if (dx,dy) is an OK place to move @@ -626,137 +626,137 @@ int mode; * Check for physical obstacles. First, the place we are going. */ if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) { - if (Blind && mode == DO_MOVE) feel_location(x,y); - if (Passes_walls && may_passwall(x,y)) { - ; /* do nothing */ - } else if (tmpr->typ == IRONBARS) { - if (!(Passes_walls || passes_bars(youmonst.data))) - return FALSE; - } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { - /* Eat the rock. */ - if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; - } else if (flags.autodig && !context.run && !context.nopick && - uwep && is_pick(uwep)) { - /* MRKR: Automatic digging when wielding the appropriate tool */ - if (mode == DO_MOVE) - (void) use_pick_axe2(uwep); - return FALSE; - } else { - if (mode == DO_MOVE) { - if (Is_stronghold(&u.uz) && is_db_wall(x,y)) - pline_The("drawbridge is up!"); - /* sokoban restriction stays even after puzzle is solved */ - if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz)) - pline_The("Sokoban walls resist your ability."); - } - return FALSE; - } + if (Blind && mode == DO_MOVE) feel_location(x,y); + if (Passes_walls && may_passwall(x,y)) { + ; /* do nothing */ + } else if (tmpr->typ == IRONBARS) { + if (!(Passes_walls || passes_bars(youmonst.data))) + return FALSE; + } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { + /* Eat the rock. */ + if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; + } else if (flags.autodig && !context.run && !context.nopick && + uwep && is_pick(uwep)) { + /* MRKR: Automatic digging when wielding the appropriate tool */ + if (mode == DO_MOVE) + (void) use_pick_axe2(uwep); + return FALSE; + } else { + if (mode == DO_MOVE) { + if (Is_stronghold(&u.uz) && is_db_wall(x,y)) + pline_The("drawbridge is up!"); + /* sokoban restriction stays even after puzzle is solved */ + if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz)) + pline_The("Sokoban walls resist your ability."); + } + return FALSE; + } } else if (IS_DOOR(tmpr->typ)) { - if (closed_door(x,y)) { - if (Blind && mode == DO_MOVE) feel_location(x,y); - if (Passes_walls) - ; /* do nothing */ - else if (can_ooze(&youmonst)) { - if (mode == DO_MOVE) You("ooze under the door."); - } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { - /* Eat the door. */ - if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; - } else { - if (mode == DO_MOVE) { - if (amorphous(youmonst.data)) - You("try to ooze under the door, but can't squeeze your possessions through."); - else if (x == ux || y == uy) { - if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) { - if (u.usteed) { - You_cant("lead %s through that closed door.", - y_monnam(u.usteed)); - } else { - pline("Ouch! You bump into a door."); - exercise(A_DEX, FALSE); - } - } else pline("That door is closed."); - } - } else if (mode == TEST_TRAV) goto testdiag; - return FALSE; - } - } else { - testdiag: - if (dx && dy && !Passes_walls - && (!doorless_door(x, y) || block_door(x, y))) { - /* Diagonal moves into a door are not allowed. */ - if (Blind && mode == DO_MOVE) - feel_location(x,y); - return FALSE; - } - } + if (closed_door(x,y)) { + if (Blind && mode == DO_MOVE) feel_location(x,y); + if (Passes_walls) + ; /* do nothing */ + else if (can_ooze(&youmonst)) { + if (mode == DO_MOVE) You("ooze under the door."); + } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { + /* Eat the door. */ + if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; + } else { + if (mode == DO_MOVE) { + if (amorphous(youmonst.data)) + You("try to ooze under the door, but can't squeeze your possessions through."); + else if (x == ux || y == uy) { + if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) { + if (u.usteed) { + You_cant("lead %s through that closed door.", + y_monnam(u.usteed)); + } else { + pline("Ouch! You bump into a door."); + exercise(A_DEX, FALSE); + } + } else pline("That door is closed."); + } + } else if (mode == TEST_TRAV) goto testdiag; + return FALSE; + } + } else { + testdiag: + if (dx && dy && !Passes_walls + && (!doorless_door(x, y) || block_door(x, y))) { + /* Diagonal moves into a door are not allowed. */ + if (Blind && mode == DO_MOVE) + feel_location(x,y); + return FALSE; + } + } } if (dx && dy - && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) { - /* Move at a diagonal. */ - switch (cant_squeeze_thru(&youmonst)) { - case 3: - if (mode == DO_MOVE) You("cannot pass that way."); - return FALSE; - case 2: - if (mode == DO_MOVE) You("are carrying too much to get through."); - return FALSE; - case 1: - if (mode == DO_MOVE) Your("body is too large to fit through."); - return FALSE; - default: - break; /* can squeeze through */ - } + && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) { + /* Move at a diagonal. */ + switch (cant_squeeze_thru(&youmonst)) { + case 3: + if (mode == DO_MOVE) You("cannot pass that way."); + return FALSE; + case 2: + if (mode == DO_MOVE) You("are carrying too much to get through."); + return FALSE; + case 1: + if (mode == DO_MOVE) Your("body is too large to fit through."); + return FALSE; + default: + break; /* can squeeze through */ + } } else if (dx && dy && worm_cross(ux, uy, x, y)) { - /* consecutive long worm segments are at and */ - if (mode == DO_MOVE) pline("%s is in your way.", Monnam(m_at(ux, y))); - return FALSE; + /* consecutive long worm segments are at and */ + if (mode == DO_MOVE) pline("%s is in your way.", Monnam(m_at(ux, y))); + return FALSE; } /* Pick travel path that does not require crossing a trap. * Avoid water and lava using the usual running rules. * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */ if (context.run == 8 && mode != DO_MOVE && (x != u.ux || y != u.uy)) { - struct trap* t = t_at(x, y); + struct trap* t = t_at(x, y); - if ((t && t->tseen) || - (!Levitation && !Flying && - !is_clinger(youmonst.data) && - is_pool_or_lava(x, y) && levl[x][y].seenv)) - return FALSE; + if ((t && t->tseen) || + (!Levitation && !Flying && + !is_clinger(youmonst.data) && + is_pool_or_lava(x, y) && levl[x][y].seenv)) + return FALSE; } ust = &levl[ux][uy]; /* Now see if other things block our way . . */ if (dx && dy && !Passes_walls && IS_DOOR(ust->typ) && - (!doorless_door(ux, uy) || block_entry(x, y))) { - /* Can't move at a diagonal out of a doorway with door. */ - return FALSE; + (!doorless_door(ux, uy) || block_entry(x, y))) { + /* Can't move at a diagonal out of a doorway with door. */ + return FALSE; } if (sobj_at(BOULDER,x,y) && (Sokoban || !Passes_walls)) { - if (!(Blind || Hallucination) && (context.run >= 2) && mode != TEST_TRAV) - return FALSE; - if (mode == DO_MOVE) { - /* tunneling monsters will chew before pushing */ - if (tunnels(youmonst.data) && !needspick(youmonst.data) && - !Sokoban) { - if (still_chewing(x,y)) return FALSE; - } else - if (moverock() < 0) return FALSE; - } else if (mode == TEST_TRAV) { - struct obj* obj; - - /* don't pick two boulders in a row, unless there's a way thru */ - if (sobj_at(BOULDER,ux,uy) && !Sokoban) { - if (!Passes_walls && - !(tunnels(youmonst.data) && !needspick(youmonst.data)) && - !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) && - !((obj = carrying(WAN_DIGGING)) && - !objects[obj->otyp].oc_name_known)) - return FALSE; - } - } - /* assume you'll be able to push it when you get there... */ + if (!(Blind || Hallucination) && (context.run >= 2) && mode != TEST_TRAV) + return FALSE; + if (mode == DO_MOVE) { + /* tunneling monsters will chew before pushing */ + if (tunnels(youmonst.data) && !needspick(youmonst.data) && + !Sokoban) { + if (still_chewing(x,y)) return FALSE; + } else + if (moverock() < 0) return FALSE; + } else if (mode == TEST_TRAV) { + struct obj* obj; + + /* don't pick two boulders in a row, unless there's a way thru */ + if (sobj_at(BOULDER,ux,uy) && !Sokoban) { + if (!Passes_walls && + !(tunnels(youmonst.data) && !needspick(youmonst.data)) && + !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) && + !((obj = carrying(WAN_DIGGING)) && + !objects[obj->otyp].oc_name_known)) + return FALSE; + } + } + /* assume you'll be able to push it when you get there... */ } /* OK, it is a legal place to move. */ @@ -769,8 +769,8 @@ static boolean trav_debug = FALSE; int wiz_debug_cmd_traveldisplay() /* in this case, toggle display of travel debug info */ { - trav_debug = !trav_debug; - return 0; + trav_debug = !trav_debug; + return 0; } #endif /* DEBUG */ @@ -786,173 +786,173 @@ boolean guess; { /* if travel to adjacent, reachable location, use normal movement rules */ if (!guess && context.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1 && - !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) { - context.run = 0; - if (test_move(u.ux, u.uy, u.tx-u.ux, u.ty-u.uy, TEST_MOVE)) { - u.dx = u.tx-u.ux; - u.dy = u.ty-u.uy; - nomul(0); - iflags.travelcc.x = iflags.travelcc.y = -1; - return TRUE; - } - context.run = 8; + !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) { + context.run = 0; + if (test_move(u.ux, u.uy, u.tx-u.ux, u.ty-u.uy, TEST_MOVE)) { + u.dx = u.tx-u.ux; + u.dy = u.ty-u.uy; + nomul(0); + iflags.travelcc.x = iflags.travelcc.y = -1; + return TRUE; + } + context.run = 8; } if (u.tx != u.ux || u.ty != u.uy) { - xchar travel[COLNO][ROWNO]; - xchar travelstepx[2][COLNO*ROWNO]; - xchar travelstepy[2][COLNO*ROWNO]; - xchar tx, ty, ux, uy; - int n = 1; /* max offset in travelsteps */ - int set = 0; /* two sets current and previous */ - int radius = 1; /* search radius */ - int i; - - /* If guessing, first find an "obvious" goal location. The obvious - * goal is the position the player knows of, or might figure out - * (couldsee) that is closest to the target on a straight path. - */ - if (guess) { - tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty; - } else { - tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy; - } + xchar travel[COLNO][ROWNO]; + xchar travelstepx[2][COLNO*ROWNO]; + xchar travelstepy[2][COLNO*ROWNO]; + xchar tx, ty, ux, uy; + int n = 1; /* max offset in travelsteps */ + int set = 0; /* two sets current and previous */ + int radius = 1; /* search radius */ + int i; + + /* If guessing, first find an "obvious" goal location. The obvious + * goal is the position the player knows of, or might figure out + * (couldsee) that is closest to the target on a straight path. + */ + if (guess) { + tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty; + } else { + tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy; + } noguess: - (void) memset((genericptr_t)travel, 0, sizeof(travel)); - travelstepx[0][0] = tx; - travelstepy[0][0] = ty; - - while (n != 0) { - int nn = 0; - - for (i = 0; i < n; i++) { - int dir; - int x = travelstepx[set][i]; - int y = travelstepy[set][i]; - static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 }; - /* no diagonal movement for grid bugs */ - int dirmax = NODIAG(u.umonnum) ? 4 : 8; - - for (dir = 0; dir < dirmax; ++dir) { - int nx = x+xdir[ordered[dir]]; - int ny = y+ydir[ordered[dir]]; - - if (!isok(nx, ny)) continue; - if ((!Passes_walls && !can_ooze(&youmonst) && - closed_door(x, y)) || sobj_at(BOULDER, x, y)) { - /* closed doors and boulders usually - * cause a delay, so prefer another path */ - if (travel[x][y] > radius-3) { - travelstepx[1-set][nn] = x; - travelstepy[1-set][nn] = y; - /* don't change travel matrix! */ - nn++; - continue; - } - } - if (test_move(x, y, nx-x, ny-y, TEST_TRAV) && - (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) { - if (nx == ux && ny == uy) { - if (!guess) { - u.dx = x-ux; - u.dy = y-uy; - if (x == u.tx && y == u.ty) { - nomul(0); - /* reset run so domove run checks work */ - context.run = 8; - iflags.travelcc.x = iflags.travelcc.y = -1; - } - return TRUE; - } - } else if (!travel[nx][ny]) { - travelstepx[1-set][nn] = nx; - travelstepy[1-set][nn] = ny; - travel[nx][ny] = radius; - nn++; - } - } - } - } + (void) memset((genericptr_t)travel, 0, sizeof(travel)); + travelstepx[0][0] = tx; + travelstepy[0][0] = ty; + + while (n != 0) { + int nn = 0; + + for (i = 0; i < n; i++) { + int dir; + int x = travelstepx[set][i]; + int y = travelstepy[set][i]; + static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 }; + /* no diagonal movement for grid bugs */ + int dirmax = NODIAG(u.umonnum) ? 4 : 8; + + for (dir = 0; dir < dirmax; ++dir) { + int nx = x+xdir[ordered[dir]]; + int ny = y+ydir[ordered[dir]]; + + if (!isok(nx, ny)) continue; + if ((!Passes_walls && !can_ooze(&youmonst) && + closed_door(x, y)) || sobj_at(BOULDER, x, y)) { + /* closed doors and boulders usually + * cause a delay, so prefer another path */ + if (travel[x][y] > radius-3) { + travelstepx[1-set][nn] = x; + travelstepy[1-set][nn] = y; + /* don't change travel matrix! */ + nn++; + continue; + } + } + if (test_move(x, y, nx-x, ny-y, TEST_TRAV) && + (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) { + if (nx == ux && ny == uy) { + if (!guess) { + u.dx = x-ux; + u.dy = y-uy; + if (x == u.tx && y == u.ty) { + nomul(0); + /* reset run so domove run checks work */ + context.run = 8; + iflags.travelcc.x = iflags.travelcc.y = -1; + } + return TRUE; + } + } else if (!travel[nx][ny]) { + travelstepx[1-set][nn] = nx; + travelstepy[1-set][nn] = ny; + travel[nx][ny] = radius; + nn++; + } + } + } + } #ifdef DEBUG - if (trav_debug) { - /* Use of warning glyph is arbitrary. It stands out. */ - tmp_at(DISP_ALL, warning_to_glyph(1)); - for (i = 0; i < nn; ++i) { - tmp_at(travelstepx[1-set][i], travelstepy[1-set][i]); - } - delay_output(); - if (flags.runmode == RUN_CRAWL) { - delay_output(); - delay_output(); - } - tmp_at(DISP_END,0); - } + if (trav_debug) { + /* Use of warning glyph is arbitrary. It stands out. */ + tmp_at(DISP_ALL, warning_to_glyph(1)); + for (i = 0; i < nn; ++i) { + tmp_at(travelstepx[1-set][i], travelstepy[1-set][i]); + } + delay_output(); + if (flags.runmode == RUN_CRAWL) { + delay_output(); + delay_output(); + } + tmp_at(DISP_END,0); + } #endif /* DEBUG */ - n = nn; - set = 1-set; - radius++; - } - - /* if guessing, find best location in travel matrix and go there */ - if (guess) { - int px = tx, py = ty; /* pick location */ - int dist, nxtdist, d2, nd2; - - dist = distmin(ux, uy, tx, ty); - d2 = dist2(ux, uy, tx, ty); - for (tx = 1; tx < COLNO; ++tx) - for (ty = 0; ty < ROWNO; ++ty) - if (travel[tx][ty]) { - nxtdist = distmin(ux, uy, tx, ty); - if (nxtdist == dist && couldsee(tx, ty)) { - nd2 = dist2(ux, uy, tx, ty); - if (nd2 < d2) { - /* prefer non-zigzag path */ - px = tx; py = ty; - d2 = nd2; - } - } else if (nxtdist < dist && couldsee(tx, ty)) { - px = tx; py = ty; - dist = nxtdist; - d2 = dist2(ux, uy, tx, ty); - } - } - - if (px == u.ux && py == u.uy) { - /* no guesses, just go in the general direction */ - u.dx = sgn(u.tx - u.ux); - u.dy = sgn(u.ty - u.uy); - if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE)) - return TRUE; - goto found; - } + n = nn; + set = 1-set; + radius++; + } + + /* if guessing, find best location in travel matrix and go there */ + if (guess) { + int px = tx, py = ty; /* pick location */ + int dist, nxtdist, d2, nd2; + + dist = distmin(ux, uy, tx, ty); + d2 = dist2(ux, uy, tx, ty); + for (tx = 1; tx < COLNO; ++tx) + for (ty = 0; ty < ROWNO; ++ty) + if (travel[tx][ty]) { + nxtdist = distmin(ux, uy, tx, ty); + if (nxtdist == dist && couldsee(tx, ty)) { + nd2 = dist2(ux, uy, tx, ty); + if (nd2 < d2) { + /* prefer non-zigzag path */ + px = tx; py = ty; + d2 = nd2; + } + } else if (nxtdist < dist && couldsee(tx, ty)) { + px = tx; py = ty; + dist = nxtdist; + d2 = dist2(ux, uy, tx, ty); + } + } + + if (px == u.ux && py == u.uy) { + /* no guesses, just go in the general direction */ + u.dx = sgn(u.tx - u.ux); + u.dy = sgn(u.ty - u.uy); + if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE)) + return TRUE; + goto found; + } #ifdef DEBUG - if (trav_debug) { - /* Use of warning glyph is arbitrary. It stands out. */ - tmp_at(DISP_ALL, warning_to_glyph(2)); - tmp_at(px, py); - delay_output(); - if (flags.runmode == RUN_CRAWL) { - delay_output(); - delay_output(); - delay_output(); - delay_output(); - } - tmp_at(DISP_END,0); - } + if (trav_debug) { + /* Use of warning glyph is arbitrary. It stands out. */ + tmp_at(DISP_ALL, warning_to_glyph(2)); + tmp_at(px, py); + delay_output(); + if (flags.runmode == RUN_CRAWL) { + delay_output(); + delay_output(); + delay_output(); + delay_output(); + } + tmp_at(DISP_END,0); + } #endif /* DEBUG */ - tx = px; - ty = py; - ux = u.ux; - uy = u.uy; - set = 0; - n = radius = 1; - guess = FALSE; - goto noguess; - } - return FALSE; + tx = px; + ty = py; + ux = u.ux; + uy = u.uy; + set = 0; + n = radius = 1; + guess = FALSE; + goto noguess; + } + return FALSE; } found: @@ -978,117 +978,117 @@ struct trap *desttrap; /* nonnull if another trap at */ switch (u.utraptype) { case TT_BEARTRAP: - if (flags.verbose) { - predicament = "caught in a bear trap"; - if (u.usteed) - Norep("%s is %s.", upstart(steedname), predicament); - else - Norep("You are %s.", predicament); - } - /* [why does diagonal movement give quickest escape?] */ - if ((u.dx && u.dy) || !rn2(5)) u.utrap--; - break; + if (flags.verbose) { + predicament = "caught in a bear trap"; + if (u.usteed) + Norep("%s is %s.", upstart(steedname), predicament); + else + Norep("You are %s.", predicament); + } + /* [why does diagonal movement give quickest escape?] */ + if ((u.dx && u.dy) || !rn2(5)) u.utrap--; + break; case TT_PIT: - if (desttrap && desttrap->tseen && - (desttrap->ttyp == PIT || desttrap->ttyp == SPIKED_PIT)) - return TRUE; /* move into adjacent pit */ - /* try to escape; position stays same regardless of success */ - climb_pit(); - break; + if (desttrap && desttrap->tseen && + (desttrap->ttyp == PIT || desttrap->ttyp == SPIKED_PIT)) + return TRUE; /* move into adjacent pit */ + /* try to escape; position stays same regardless of success */ + climb_pit(); + break; case TT_WEB: - if (uwep && uwep->oartifact == ART_STING) { - u.utrap = 0; - pline("Sting cuts through the web!"); - break; /* escape trap but don't move */ - } - if (--u.utrap) { - if (flags.verbose) { - predicament = "stuck to the web"; - if (u.usteed) - Norep("%s is %s.", upstart(steedname), predicament); - else - Norep("You are %s.", predicament); - } - } else { - if (u.usteed) - pline("%s breaks out of the web.", upstart(steedname)); - else - You("disentangle yourself."); - } - break; + if (uwep && uwep->oartifact == ART_STING) { + u.utrap = 0; + pline("Sting cuts through the web!"); + break; /* escape trap but don't move */ + } + if (--u.utrap) { + if (flags.verbose) { + predicament = "stuck to the web"; + if (u.usteed) + Norep("%s is %s.", upstart(steedname), predicament); + else + Norep("You are %s.", predicament); + } + } else { + if (u.usteed) + pline("%s breaks out of the web.", upstart(steedname)); + else + You("disentangle yourself."); + } + break; case TT_LAVA: - if (flags.verbose) { - predicament = "stuck in the lava"; - if (u.usteed) - Norep("%s is %s.", upstart(steedname), predicament); - else - Norep("You are %s.", predicament); - } - if (!is_lava(x, y)) { - u.utrap--; - if ((u.utrap & 0xff) == 0) { - u.utrap = 0; - if (u.usteed) - You("lead %s to the edge of the lava.", steedname); - else - You("pull yourself to the edge of the lava."); - } - } - u.umoved = TRUE; - break; + if (flags.verbose) { + predicament = "stuck in the lava"; + if (u.usteed) + Norep("%s is %s.", upstart(steedname), predicament); + else + Norep("You are %s.", predicament); + } + if (!is_lava(x, y)) { + u.utrap--; + if ((u.utrap & 0xff) == 0) { + u.utrap = 0; + if (u.usteed) + You("lead %s to the edge of the lava.", steedname); + else + You("pull yourself to the edge of the lava."); + } + } + u.umoved = TRUE; + break; case TT_INFLOOR: case TT_BURIEDBALL: - anchored = (u.utraptype == TT_BURIEDBALL); - if (anchored) { - coord cc; - - cc.x = u.ux, cc.y = u.uy; - /* can move normally within radius 1 of buried ball */ - if (buried_ball(&cc) && dist2(x, y, cc.x, cc.y) <= 2) { - /* ugly hack: we need to issue some message here - in case "you are chained to the buried ball" - was the most recent message given, otherwise - our next attempt to move out of tether range - after this successful move would have its - can't-do-that message suppressed by Norep */ - if (flags.verbose) - Norep("You move within the chain's reach."); - return TRUE; - } - } - if (--u.utrap) { - if (flags.verbose) { - if (anchored) { - predicament = "chained to the"; - culprit = "buried ball"; - } else { - predicament = "stuck in the"; - culprit = surface(u.ux, u.uy); - } - if (u.usteed) { - if (anchored) - Norep("You and %s are %s %s.", steedname, - predicament, culprit); - else - Norep("%s is %s %s.", upstart(steedname), - predicament, culprit); - } else - Norep("You are %s %s.", predicament, culprit); - } - } else { - if (u.usteed) - pline("%s finally %s free.", upstart(steedname), - !anchored ? "lurches" : "wrenches the ball"); - else - You("finally %s free.", - !anchored ? "wriggle" : "wrench the ball"); - if (anchored) - buried_ball_to_punishment(); - } - break; + anchored = (u.utraptype == TT_BURIEDBALL); + if (anchored) { + coord cc; + + cc.x = u.ux, cc.y = u.uy; + /* can move normally within radius 1 of buried ball */ + if (buried_ball(&cc) && dist2(x, y, cc.x, cc.y) <= 2) { + /* ugly hack: we need to issue some message here + in case "you are chained to the buried ball" + was the most recent message given, otherwise + our next attempt to move out of tether range + after this successful move would have its + can't-do-that message suppressed by Norep */ + if (flags.verbose) + Norep("You move within the chain's reach."); + return TRUE; + } + } + if (--u.utrap) { + if (flags.verbose) { + if (anchored) { + predicament = "chained to the"; + culprit = "buried ball"; + } else { + predicament = "stuck in the"; + culprit = surface(u.ux, u.uy); + } + if (u.usteed) { + if (anchored) + Norep("You and %s are %s %s.", steedname, + predicament, culprit); + else + Norep("%s is %s %s.", upstart(steedname), + predicament, culprit); + } else + Norep("You are %s %s.", predicament, culprit); + } + } else { + if (u.usteed) + pline("%s finally %s free.", upstart(steedname), + !anchored ? "lurches" : "wrenches the ball"); + else + You("finally %s free.", + !anchored ? "wriggle" : "wrench the ball"); + if (anchored) + buried_ball_to_punishment(); + } + break; default: - impossible("trapmove: stuck in unknown trap? (%d)", (int)u.utraptype); - break; + impossible("trapmove: stuck in unknown trap? (%d)", (int)u.utraptype); + break; } return FALSE; } @@ -1096,490 +1096,490 @@ struct trap *desttrap; /* nonnull if another trap at */ void domove() { - register struct monst *mtmp; - register struct rm *tmpr; - register xchar x,y; - struct trap *trap; - int wtcap; - boolean on_ice; - xchar chainx, chainy, ballx, bally; /* ball&chain new positions */ - int bc_control; /* control for ball&chain */ - boolean cause_delay = FALSE; /* dragging ball will skip a move */ - - u_wipe_engr(rnd(5)); - - if (context.travel) { - if (!findtravelpath(FALSE)) - (void) findtravelpath(TRUE); - context.travel1 = 0; - } - - if(((wtcap = near_capacity()) >= OVERLOADED - || (wtcap > SLT_ENCUMBER && - (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) - : (u.uhp < 10 && u.uhp != u.uhpmax)))) - && !Is_airlevel(&u.uz)) { - if(wtcap < OVERLOADED) { - You("don't have enough stamina to move."); - exercise(A_CON, FALSE); - } else - You("collapse under your load."); - nomul(0); - return; - } - if(u.uswallow) { - u.dx = u.dy = 0; - u.ux = x = u.ustuck->mx; - u.uy = y = u.ustuck->my; - mtmp = u.ustuck; - } else { - if (Is_airlevel(&u.uz) && rn2(4) && - !Levitation && !Flying) { - switch(rn2(3)) { - case 0: - You("tumble in place."); - exercise(A_DEX, FALSE); - break; - case 1: - You_cant("control your movements very well."); break; - case 2: - pline("It's hard to walk in thin air."); - exercise(A_DEX, TRUE); - break; - } - return; - } - - /* check slippery ice */ - on_ice = !Levitation && is_ice(u.ux, u.uy); - if (on_ice) { - static int skates = 0; - if (!skates) skates = find_skates(); - if ((uarmf && uarmf->otyp == skates) - || resists_cold(&youmonst) || Flying - || is_floater(youmonst.data) || is_clinger(youmonst.data) - || is_whirly(youmonst.data)) - on_ice = FALSE; - else if (!rn2(Cold_resistance ? 3 : 2)) { - HFumbling |= FROMOUTSIDE; - HFumbling &= ~TIMEOUT; - HFumbling += 1; /* slip on next move */ - } - } - if (!on_ice && (HFumbling & FROMOUTSIDE)) - HFumbling &= ~FROMOUTSIDE; - - x = u.ux + u.dx; - y = u.uy + u.dy; - if(Stunned || (Confusion && !rn2(5))) { - register int tries = 0; - - do { - if(tries++ > 50) { - nomul(0); - return; - } - confdir(); - x = u.ux + u.dx; - y = u.uy + u.dy; - } while(!isok(x, y) || bad_rock(youmonst.data, x, y)); - } - /* turbulence might alter your actual destination */ - if (u.uinwater) { - water_friction(); - if (!u.dx && !u.dy) { - nomul(0); - return; - } - x = u.ux + u.dx; - y = u.uy + u.dy; - } - if(!isok(x, y)) { - nomul(0); - return; - } - if (((trap = t_at(x, y)) && trap->tseen) || - (Blind && !Levitation && !Flying && - !is_clinger(youmonst.data) && - is_pool_or_lava(x, y) && levl[x][y].seenv)) { - if(context.run >= 2) { - nomul(0); - context.move = 0; - return; - } else - nomul(0); - } - - if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) { - if (distu(u.ustuck->mx, u.ustuck->my) > 2) { - /* perhaps it fled (or was teleported or ... ) */ - u.ustuck = 0; - } else if (sticks(youmonst.data)) { - /* When polymorphed into a sticking monster, - * u.ustuck means it's stuck to you, not you to it. - */ - You("release %s.", mon_nam(u.ustuck)); - u.ustuck = 0; - } else { - /* If holder is asleep or paralyzed: - * 37.5% chance of getting away, - * 12.5% chance of waking/releasing it; - * otherwise: - * 7.5% chance of getting away. - * [strength ought to be a factor] - * If holder is tame and there is no conflict, - * guaranteed escape. - */ - switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) { - case 0: case 1: case 2: - pull_free: - You("pull free from %s.", mon_nam(u.ustuck)); - u.ustuck = 0; - break; - case 3: - if (!u.ustuck->mcanmove) { - /* it's free to move on next turn */ - u.ustuck->mfrozen = 1; - u.ustuck->msleeping = 0; - } - /*FALLTHRU*/ - default: - if (u.ustuck->mtame && - !Conflict && !u.ustuck->mconf) - goto pull_free; - You("cannot escape from %s!", mon_nam(u.ustuck)); - nomul(0); - return; - } - } - } - - mtmp = m_at(x,y); - if (mtmp) { - /* Don't attack if you're running, and can see it */ - /* We should never get here if forcefight */ - if (context.run && - ((!Blind && mon_visible(mtmp) && - ((mtmp->m_ap_type != M_AP_FURNITURE && - mtmp->m_ap_type != M_AP_OBJECT) || - Protection_from_shape_changers)) || - sensemon(mtmp))) { - nomul(0); - context.move = 0; - return; - } - } - } - - u.ux0 = u.ux; - u.uy0 = u.uy; - bhitpos.x = x; - bhitpos.y = y; - tmpr = &levl[x][y]; - - /* attack monster */ - if(mtmp) { - nomul(0); - /* only attack if we know it's there */ - /* or if we used the 'F' command to fight blindly */ - /* or if it hides_under, in which case we call attack() to print - * the Wait! message. - * This is different from ceiling hiders, who aren't handled in - * attack(). - */ - - /* If they used a 'm' command, trying to move onto a monster - * prints the below message and wastes a turn. The exception is - * if the monster is unseen and the player doesn't remember an - * invisible monster--then, we fall through to attack() and - * attack_check(), which still wastes a turn, but prints a - * different message and makes the player remember the monster. */ - if(context.nopick && - (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){ - if(mtmp->m_ap_type && !Protection_from_shape_changers - && !sensemon(mtmp)) - stumble_onto_mimic(mtmp); - else if (mtmp->mpeaceful && !Hallucination) - pline("Pardon me, %s.", m_monnam(mtmp)); - else - You("move right into %s.", mon_nam(mtmp)); - return; - } - if(context.forcefight || !mtmp->mundetected || sensemon(mtmp) || - ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) && - !is_safepet(mtmp))){ - /* try to attack; note that it might evade */ - /* also, we don't attack tame when _safepet_ */ - if(attack(mtmp)) return; - } - } - - /* specifying 'F' with no monster wastes a turn */ - if (context.forcefight || - /* remembered an 'I' && didn't use a move command */ - (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) { - struct obj *boulder = sobj_at(BOULDER, x, y); - boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)), - solid = !accessible(x, y); - int glyph = glyph_at(x, y); /* might be monster */ - char buf[BUFSZ]; - - /* if a statue is displayed at the target location, - player is attempting to attack it [and boulder - handlng below is suitable for handling that] */ - if (glyph_is_statue(glyph) || - (Hallucination && glyph_is_monster(glyph))) - boulder = sobj_at(STATUE, x, y); - - /* force fight at boulder/statue or wall/door while wielding - pick: start digging to break the boulder or wall */ - if (context.forcefight && - /* can we dig? */ - uwep && dig_typ(uwep, x, y) && - /* should we dig? */ - !glyph_is_invisible(glyph) && - !glyph_is_monster(glyph)) { - (void)use_pick_axe2(uwep); - return; - } - - if (boulder) - Strcpy(buf, ansimpleoname(boulder)); - else if (solid) - Strcpy(buf, the(defsyms[glyph_to_cmap(glyph)].explanation)); - else if (!Underwater) - Strcpy(buf, "thin air"); - else if (is_pool(x, y)) - Strcpy(buf, "empty water"); - else /* Underwater, targetting non-water */ - Sprintf(buf, "a vacant spot on the %s", surface(x,y)); - You("%s%s %s.", - !(boulder || solid) ? "" : - !explo ? "harmlessly " : "futilely ", - explo ? "explode at" : "attack", - buf); - unmap_object(x, y); /* known empty -- remove 'I' if present */ - if (boulder) map_object(boulder, TRUE); - newsym(x, y); - nomul(0); - if (explo) { - wake_nearby(); - u.mh = -1; /* dead in the current form */ - rehumanize(); - } - return; - } - if (glyph_is_invisible(levl[x][y].glyph)) { - unmap_object(x, y); - newsym(x, y); - } - /* not attacking an animal, so we try to move */ - if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) { - nomul(0); - return; - } - if(!youmonst.data->mmove) { - You("are rooted %s.", - Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? - "in place" : "to the ground"); - nomul(0); - return; - } - if(u.utrap) { - if (!trapmove(x, y, trap)) return; - } - - if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) { - context.move = 0; - nomul(0); - return; - } - - /* Move ball and chain. */ - if (Punished) - if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy, - &cause_delay, TRUE)) - return; - - /* Check regions entering/leaving */ - if (!in_out_region(x,y)) - return; - - /* now move the hero */ - mtmp = m_at(x, y); - u.ux += u.dx; - u.uy += u.dy; - /* Move your steed, too */ - if (u.usteed) { - u.usteed->mx = u.ux; - u.usteed->my = u.uy; - exercise_steed(); - } - - /* - * If safepet at destination then move the pet to the hero's - * previous location using the same conditions as in attack(). - * there are special extenuating circumstances: - * (1) if the pet dies then your god angers, - * (2) if the pet gets trapped then your god may disapprove, - * (3) if the pet was already trapped and you attempt to free it - * not only do you encounter the trap but you may frighten your - * pet causing it to go wild! moral: don't abuse this privilege. - * - * Ceiling-hiding pets are skipped by this section of code, to - * be caught by the normal falling-monster code. - */ - if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) { - /* if trapped, there's a chance the pet goes wild */ - if (mtmp->mtrapped) { - if (!rn2(mtmp->mtame)) { - mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0; - if (mtmp->mleashed) m_unleash(mtmp, TRUE); - growl(mtmp); - } else { - yelp(mtmp); - } - } - mtmp->mundetected = 0; - if (mtmp->m_ap_type) seemimic(mtmp); - else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); - - if (mtmp->mtrapped && - (trap = t_at(mtmp->mx, mtmp->my)) != 0 && - (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && - sobj_at(BOULDER, trap->tx, trap->ty)) { - /* can't swap places with pet pinned in a pit by a boulder */ - u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ - } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { - /* can't swap places when pet can't move to your spot */ - u.ux = u.ux0, u.uy = u.uy0; - You("stop. %s can't move diagonally.", - upstart(y_monnam(mtmp))); - } else if (u.ux0 != x && u.uy0 != y && - bad_rock(mtmp->data, x, u.uy0) && - bad_rock(mtmp->data, u.ux0, y) && - (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { - /* can't swap places when pet won't fit thru the opening */ - u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ - You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); - } else { - char pnambuf[BUFSZ]; - - /* save its current description in case of polymorph */ - Strcpy(pnambuf, y_monnam(mtmp)); - mtmp->mtrapped = 0; - remove_monster(x, y); - place_monster(mtmp, u.ux0, u.uy0); - newsym(x, y); - newsym(u.ux0, u.uy0); - - You("%s %s.", mtmp->mtame ? "swap places with" : "frighten", - pnambuf); - - /* check for displacing it into pools and traps */ - switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { - case 0: - break; - case 1: /* trapped */ - case 3: /* changed levels */ - /* there's already been a trap message, reinforce it */ - abuse_dog(mtmp); - adjalign(-3); - break; - case 2: - /* drowned or died... - * you killed your pet by direct action, so get experience - * and possibly penalties; - * we want the level gain message, if it happens, to occur - * before the guilt message below - */ - { - /* minliquid() and mintrap() call mondead() rather than - killed() so we duplicate some of the latter here */ - int tmp, mndx; - - u.uconduct.killer++; - mndx = monsndx(mtmp->data); - tmp = experience(mtmp, (int)mvitals[mndx].died); - more_experienced(tmp, 0); - newexplevel(); /* will decide if you go up */ - } - /* That's no way to treat a pet! Your god gets angry. - * - * [This has always been pretty iffy. Why does your - * patron deity care at all, let alone enough to get mad?] - */ - if (rn2(4)) { - You_feel("guilty about losing your pet like this."); - u.ugangr++; - adjalign(-15); - } - break; - default: - pline("that's strange, unknown mintrap result!"); - break; - } - } - } - - reset_occupations(); - if (context.run) { - if ( context.run < 8 ) - if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) || - IS_FURNITURE(tmpr->typ)) - nomul(0); - } - - if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) || - u.dx || u.dy) - (void) hideunder(&youmonst); - - /* - * Mimics (or whatever) become noticeable if they move and are - * imitating something that doesn't move. We could extend this - * to non-moving monsters... - */ - if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT - || youmonst.m_ap_type == M_AP_FURNITURE)) - youmonst.m_ap_type = M_AP_NOTHING; - - check_leash(u.ux0,u.uy0); - - if(u.ux0 != u.ux || u.uy0 != u.uy) { - u.umoved = TRUE; - /* Clean old position -- vision_recalc() will print our new one. */ - newsym(u.ux0,u.uy0); - /* Since the hero has moved, adjust what can be seen/unseen. */ - vision_recalc(1); /* Do the work now in the recover time. */ - invocation_message(); - } - - if (Punished) /* put back ball and chain */ - move_bc(0,bc_control,ballx,bally,chainx,chainy); - - spoteffects(TRUE); - - /* delay next move because of ball dragging */ - /* must come after we finished picking up, in spoteffects() */ - if (cause_delay) { - nomul(-2); - nomovemsg = ""; - } - - if (context.run && flags.runmode != RUN_TPORT) { - /* display every step or every 7th step depending upon mode */ - if (flags.runmode != RUN_LEAP || !(moves % 7L)) { - if (flags.time) context.botl = 1; - curs_on_u(); - delay_output(); - if (flags.runmode == RUN_CRAWL) { - delay_output(); - delay_output(); - delay_output(); - delay_output(); - } - } - } + register struct monst *mtmp; + register struct rm *tmpr; + register xchar x,y; + struct trap *trap = NULL; + int wtcap; + boolean on_ice; + xchar chainx, chainy, ballx, bally; /* ball&chain new positions */ + int bc_control; /* control for ball&chain */ + boolean cause_delay = FALSE; /* dragging ball will skip a move */ + + u_wipe_engr(rnd(5)); + + if (context.travel) { + if (!findtravelpath(FALSE)) + (void) findtravelpath(TRUE); + context.travel1 = 0; + } + + if(((wtcap = near_capacity()) >= OVERLOADED + || (wtcap > SLT_ENCUMBER && + (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) + : (u.uhp < 10 && u.uhp != u.uhpmax)))) + && !Is_airlevel(&u.uz)) { + if(wtcap < OVERLOADED) { + You("don't have enough stamina to move."); + exercise(A_CON, FALSE); + } else + You("collapse under your load."); + nomul(0); + return; + } + if(u.uswallow) { + u.dx = u.dy = 0; + u.ux = x = u.ustuck->mx; + u.uy = y = u.ustuck->my; + mtmp = u.ustuck; + } else { + if (Is_airlevel(&u.uz) && rn2(4) && + !Levitation && !Flying) { + switch(rn2(3)) { + case 0: + You("tumble in place."); + exercise(A_DEX, FALSE); + break; + case 1: + You_cant("control your movements very well."); break; + case 2: + pline("It's hard to walk in thin air."); + exercise(A_DEX, TRUE); + break; + } + return; + } + + /* check slippery ice */ + on_ice = !Levitation && is_ice(u.ux, u.uy); + if (on_ice) { + static int skates = 0; + if (!skates) skates = find_skates(); + if ((uarmf && uarmf->otyp == skates) + || resists_cold(&youmonst) || Flying + || is_floater(youmonst.data) || is_clinger(youmonst.data) + || is_whirly(youmonst.data)) + on_ice = FALSE; + else if (!rn2(Cold_resistance ? 3 : 2)) { + HFumbling |= FROMOUTSIDE; + HFumbling &= ~TIMEOUT; + HFumbling += 1; /* slip on next move */ + } + } + if (!on_ice && (HFumbling & FROMOUTSIDE)) + HFumbling &= ~FROMOUTSIDE; + + x = u.ux + u.dx; + y = u.uy + u.dy; + if(Stunned || (Confusion && !rn2(5))) { + register int tries = 0; + + do { + if(tries++ > 50) { + nomul(0); + return; + } + confdir(); + x = u.ux + u.dx; + y = u.uy + u.dy; + } while(!isok(x, y) || bad_rock(youmonst.data, x, y)); + } + /* turbulence might alter your actual destination */ + if (u.uinwater) { + water_friction(); + if (!u.dx && !u.dy) { + nomul(0); + return; + } + x = u.ux + u.dx; + y = u.uy + u.dy; + } + if(!isok(x, y)) { + nomul(0); + return; + } + if (((trap = t_at(x, y)) && trap->tseen) || + (Blind && !Levitation && !Flying && + !is_clinger(youmonst.data) && + is_pool_or_lava(x, y) && levl[x][y].seenv)) { + if(context.run >= 2) { + nomul(0); + context.move = 0; + return; + } else + nomul(0); + } + + if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) { + if (distu(u.ustuck->mx, u.ustuck->my) > 2) { + /* perhaps it fled (or was teleported or ... ) */ + u.ustuck = 0; + } else if (sticks(youmonst.data)) { + /* When polymorphed into a sticking monster, + * u.ustuck means it's stuck to you, not you to it. + */ + You("release %s.", mon_nam(u.ustuck)); + u.ustuck = 0; + } else { + /* If holder is asleep or paralyzed: + * 37.5% chance of getting away, + * 12.5% chance of waking/releasing it; + * otherwise: + * 7.5% chance of getting away. + * [strength ought to be a factor] + * If holder is tame and there is no conflict, + * guaranteed escape. + */ + switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) { + case 0: case 1: case 2: + pull_free: + You("pull free from %s.", mon_nam(u.ustuck)); + u.ustuck = 0; + break; + case 3: + if (!u.ustuck->mcanmove) { + /* it's free to move on next turn */ + u.ustuck->mfrozen = 1; + u.ustuck->msleeping = 0; + } + /*FALLTHRU*/ + default: + if (u.ustuck->mtame && + !Conflict && !u.ustuck->mconf) + goto pull_free; + You("cannot escape from %s!", mon_nam(u.ustuck)); + nomul(0); + return; + } + } + } + + mtmp = m_at(x,y); + if (mtmp) { + /* Don't attack if you're running, and can see it */ + /* We should never get here if forcefight */ + if (context.run && + ((!Blind && mon_visible(mtmp) && + ((mtmp->m_ap_type != M_AP_FURNITURE && + mtmp->m_ap_type != M_AP_OBJECT) || + Protection_from_shape_changers)) || + sensemon(mtmp))) { + nomul(0); + context.move = 0; + return; + } + } + } + + u.ux0 = u.ux; + u.uy0 = u.uy; + bhitpos.x = x; + bhitpos.y = y; + tmpr = &levl[x][y]; + + /* attack monster */ + if(mtmp) { + nomul(0); + /* only attack if we know it's there */ + /* or if we used the 'F' command to fight blindly */ + /* or if it hides_under, in which case we call attack() to print + * the Wait! message. + * This is different from ceiling hiders, who aren't handled in + * attack(). + */ + + /* If they used a 'm' command, trying to move onto a monster + * prints the below message and wastes a turn. The exception is + * if the monster is unseen and the player doesn't remember an + * invisible monster--then, we fall through to attack() and + * attack_check(), which still wastes a turn, but prints a + * different message and makes the player remember the monster. */ + if(context.nopick && + (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){ + if(mtmp->m_ap_type && !Protection_from_shape_changers + && !sensemon(mtmp)) + stumble_onto_mimic(mtmp); + else if (mtmp->mpeaceful && !Hallucination) + pline("Pardon me, %s.", m_monnam(mtmp)); + else + You("move right into %s.", mon_nam(mtmp)); + return; + } + if(context.forcefight || !mtmp->mundetected || sensemon(mtmp) || + ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) && + !is_safepet(mtmp))){ + /* try to attack; note that it might evade */ + /* also, we don't attack tame when _safepet_ */ + if(attack(mtmp)) return; + } + } + + /* specifying 'F' with no monster wastes a turn */ + if (context.forcefight || + /* remembered an 'I' && didn't use a move command */ + (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) { + struct obj *boulder = sobj_at(BOULDER, x, y); + boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)), + solid = !accessible(x, y); + int glyph = glyph_at(x, y); /* might be monster */ + char buf[BUFSZ]; + + /* if a statue is displayed at the target location, + player is attempting to attack it [and boulder + handlng below is suitable for handling that] */ + if (glyph_is_statue(glyph) || + (Hallucination && glyph_is_monster(glyph))) + boulder = sobj_at(STATUE, x, y); + + /* force fight at boulder/statue or wall/door while wielding + pick: start digging to break the boulder or wall */ + if (context.forcefight && + /* can we dig? */ + uwep && dig_typ(uwep, x, y) && + /* should we dig? */ + !glyph_is_invisible(glyph) && + !glyph_is_monster(glyph)) { + (void)use_pick_axe2(uwep); + return; + } + + if (boulder) + Strcpy(buf, ansimpleoname(boulder)); + else if (solid) + Strcpy(buf, the(defsyms[glyph_to_cmap(glyph)].explanation)); + else if (!Underwater) + Strcpy(buf, "thin air"); + else if (is_pool(x, y)) + Strcpy(buf, "empty water"); + else /* Underwater, targetting non-water */ + Sprintf(buf, "a vacant spot on the %s", surface(x,y)); + You("%s%s %s.", + !(boulder || solid) ? "" : + !explo ? "harmlessly " : "futilely ", + explo ? "explode at" : "attack", + buf); + unmap_object(x, y); /* known empty -- remove 'I' if present */ + if (boulder) map_object(boulder, TRUE); + newsym(x, y); + nomul(0); + if (explo) { + wake_nearby(); + u.mh = -1; /* dead in the current form */ + rehumanize(); + } + return; + } + if (glyph_is_invisible(levl[x][y].glyph)) { + unmap_object(x, y); + newsym(x, y); + } + /* not attacking an animal, so we try to move */ + if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) { + nomul(0); + return; + } + if(!youmonst.data->mmove) { + You("are rooted %s.", + Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? + "in place" : "to the ground"); + nomul(0); + return; + } + if(u.utrap) { + if (!trapmove(x, y, trap)) return; + } + + if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) { + context.move = 0; + nomul(0); + return; + } + + /* Move ball and chain. */ + if (Punished) + if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy, + &cause_delay, TRUE)) + return; + + /* Check regions entering/leaving */ + if (!in_out_region(x,y)) + return; + + /* now move the hero */ + mtmp = m_at(x, y); + u.ux += u.dx; + u.uy += u.dy; + /* Move your steed, too */ + if (u.usteed) { + u.usteed->mx = u.ux; + u.usteed->my = u.uy; + exercise_steed(); + } + + /* + * If safepet at destination then move the pet to the hero's + * previous location using the same conditions as in attack(). + * there are special extenuating circumstances: + * (1) if the pet dies then your god angers, + * (2) if the pet gets trapped then your god may disapprove, + * (3) if the pet was already trapped and you attempt to free it + * not only do you encounter the trap but you may frighten your + * pet causing it to go wild! moral: don't abuse this privilege. + * + * Ceiling-hiding pets are skipped by this section of code, to + * be caught by the normal falling-monster code. + */ + if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) { + /* if trapped, there's a chance the pet goes wild */ + if (mtmp->mtrapped) { + if (!rn2(mtmp->mtame)) { + mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0; + if (mtmp->mleashed) m_unleash(mtmp, TRUE); + growl(mtmp); + } else { + yelp(mtmp); + } + } + mtmp->mundetected = 0; + if (mtmp->m_ap_type) seemimic(mtmp); + else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); + + if (mtmp->mtrapped && + (trap = t_at(mtmp->mx, mtmp->my)) != 0 && + (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && + sobj_at(BOULDER, trap->tx, trap->ty)) { + /* can't swap places with pet pinned in a pit by a boulder */ + u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ + } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { + /* can't swap places when pet can't move to your spot */ + u.ux = u.ux0, u.uy = u.uy0; + You("stop. %s can't move diagonally.", + upstart(y_monnam(mtmp))); + } else if (u.ux0 != x && u.uy0 != y && + bad_rock(mtmp->data, x, u.uy0) && + bad_rock(mtmp->data, u.ux0, y) && + (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { + /* can't swap places when pet won't fit thru the opening */ + u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ + You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); + } else { + char pnambuf[BUFSZ]; + + /* save its current description in case of polymorph */ + Strcpy(pnambuf, y_monnam(mtmp)); + mtmp->mtrapped = 0; + remove_monster(x, y); + place_monster(mtmp, u.ux0, u.uy0); + newsym(x, y); + newsym(u.ux0, u.uy0); + + You("%s %s.", mtmp->mtame ? "swap places with" : "frighten", + pnambuf); + + /* check for displacing it into pools and traps */ + switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { + case 0: + break; + case 1: /* trapped */ + case 3: /* changed levels */ + /* there's already been a trap message, reinforce it */ + abuse_dog(mtmp); + adjalign(-3); + break; + case 2: + /* drowned or died... + * you killed your pet by direct action, so get experience + * and possibly penalties; + * we want the level gain message, if it happens, to occur + * before the guilt message below + */ + { + /* minliquid() and mintrap() call mondead() rather than + killed() so we duplicate some of the latter here */ + int tmp, mndx; + + u.uconduct.killer++; + mndx = monsndx(mtmp->data); + tmp = experience(mtmp, (int)mvitals[mndx].died); + more_experienced(tmp, 0); + newexplevel(); /* will decide if you go up */ + } + /* That's no way to treat a pet! Your god gets angry. + * + * [This has always been pretty iffy. Why does your + * patron deity care at all, let alone enough to get mad?] + */ + if (rn2(4)) { + You_feel("guilty about losing your pet like this."); + u.ugangr++; + adjalign(-15); + } + break; + default: + pline("that's strange, unknown mintrap result!"); + break; + } + } + } + + reset_occupations(); + if (context.run) { + if ( context.run < 8 ) + if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) || + IS_FURNITURE(tmpr->typ)) + nomul(0); + } + + if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) || + u.dx || u.dy) + (void) hideunder(&youmonst); + + /* + * Mimics (or whatever) become noticeable if they move and are + * imitating something that doesn't move. We could extend this + * to non-moving monsters... + */ + if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT + || youmonst.m_ap_type == M_AP_FURNITURE)) + youmonst.m_ap_type = M_AP_NOTHING; + + check_leash(u.ux0,u.uy0); + + if(u.ux0 != u.ux || u.uy0 != u.uy) { + u.umoved = TRUE; + /* Clean old position -- vision_recalc() will print our new one. */ + newsym(u.ux0,u.uy0); + /* Since the hero has moved, adjust what can be seen/unseen. */ + vision_recalc(1); /* Do the work now in the recover time. */ + invocation_message(); + } + + if (Punished) /* put back ball and chain */ + move_bc(0,bc_control,ballx,bally,chainx,chainy); + + spoteffects(TRUE); + + /* delay next move because of ball dragging */ + /* must come after we finished picking up, in spoteffects() */ + if (cause_delay) { + nomul(-2); + nomovemsg = ""; + } + + if (context.run && flags.runmode != RUN_TPORT) { + /* display every step or every 7th step depending upon mode */ + if (flags.runmode != RUN_LEAP || !(moves % 7L)) { + if (flags.time) context.botl = 1; + curs_on_u(); + delay_output(); + if (flags.runmode == RUN_CRAWL) { + delay_output(); + delay_output(); + delay_output(); + delay_output(); + } + } + } } /* combat increases metabolism */ @@ -1591,15 +1591,15 @@ overexertion() execute if you decline to attack a peaceful monster */ gethungry(); if ((moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) { - int *hp = (!Upolyd ? &u.uhp : &u.mh); + int *hp = (!Upolyd ? &u.uhp : &u.mh); - if (*hp > 1) { - *hp -= 1; - } else { - You("pass out from exertion!"); - exercise(A_CON, FALSE); - fall_asleep(-10, FALSE); - } + if (*hp > 1) { + *hp -= 1; + } else { + You("pass out from exertion!"); + exercise(A_CON, FALSE); + fall_asleep(-10, FALSE); + } } return (multi < 0); /* might have fainted (actually gone to sleep) */ } @@ -1607,22 +1607,22 @@ overexertion() void invocation_message() { - /* a special clue-msg when on the Invocation position */ - if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { - char buf[BUFSZ]; - struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION); - - nomul(0); /* stop running or travelling */ - if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed)); - else if (Levitation || Flying) Strcpy(buf, "beneath you"); - else Sprintf(buf, "under your %s", makeplural(body_part(FOOT))); - - You_feel("a strange vibration %s.", buf); - u.uevent.uvibrated = 1; - if (otmp && otmp->spe == 7 && otmp->lamplit) - pline("%s %s!", The(xname(otmp)), - Blind ? "throbs palpably" : "glows with a strange light"); - } + /* a special clue-msg when on the Invocation position */ + if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { + char buf[BUFSZ]; + struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION); + + nomul(0); /* stop running or travelling */ + if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed)); + else if (Levitation || Flying) Strcpy(buf, "beneath you"); + else Sprintf(buf, "under your %s", makeplural(body_part(FOOT))); + + You_feel("a strange vibration %s.", buf); + u.uevent.uvibrated = 1; + if (otmp && otmp->spe == 7 && otmp->lamplit) + pline("%s %s!", The(xname(otmp)), + Blind ? "throbs palpably" : "glows with a strange light"); + } } /* moving onto different terrain; @@ -1633,27 +1633,27 @@ switch_terrain() { struct rm *lev = &levl[u.ux][u.uy]; boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy) || - (Is_waterlevel(&u.uz) && lev->typ == WATER)); + (Is_waterlevel(&u.uz) && lev->typ == WATER)); if (blocklev) { - /* called from spoteffects(), skip float_down() */ - if (Levitation) You_cant("levitate in here."); - BLevitation |= FROMOUTSIDE; + /* called from spoteffects(), skip float_down() */ + if (Levitation) You_cant("levitate in here."); + BLevitation |= FROMOUTSIDE; } else if (BLevitation) { - BLevitation &= ~FROMOUTSIDE; - if (Levitation) float_up(); + BLevitation &= ~FROMOUTSIDE; + if (Levitation) float_up(); } /* the same terrain that blocks levitation also blocks flight */ if (blocklev) { - if (Flying) You_cant("fly in here."); - BFlying |= FROMOUTSIDE; + if (Flying) You_cant("fly in here."); + BFlying |= FROMOUTSIDE; } else if (BFlying) { - BFlying &= ~FROMOUTSIDE; - float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ - /* [minor bug: we don't know whether this is beginning flight or - resuming it; that could be tracked so that this message could - be adjusted to "resume flying", but isn't worth the effort...] */ - if (Flying) You("start flying."); + BFlying &= ~FROMOUTSIDE; + float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ + /* [minor bug: we don't know whether this is beginning flight or + resuming it; that could be tracked so that this message could + be adjusted to "resume flying", but isn't worth the effort...] */ + if (Flying) You("start flying."); } } @@ -1665,67 +1665,67 @@ boolean newspot; /* true if called by spoteffects */ { /* check for leaving water */ if (u.uinwater) { - boolean still_inwater = FALSE; /* assume we're getting out */ - - if (!is_pool(u.ux,u.uy)) { - if (Is_waterlevel(&u.uz)) - You("pop into an air bubble."); - else if (is_lava(u.ux, u.uy)) - You("leave the water..."); /* oops! */ - else - You("are on solid %s again.", - is_ice(u.ux, u.uy) ? "ice" : "land"); - } else if (Is_waterlevel(&u.uz)) { - still_inwater = TRUE; - } else if (Levitation) { - You("pop out of the water like a cork!"); - } else if (Flying) { - You("fly out of the water."); - } else if (Wwalking) { - You("slowly rise above the surface."); - } else { - still_inwater = TRUE; - } - if (!still_inwater) { - boolean was_underwater = (Underwater && !Is_waterlevel(&u.uz)); - - u.uinwater = 0; /* leave the water */ - if (was_underwater) { /* restore vision */ - docrt(); - vision_full_recalc = 1; - } - } + boolean still_inwater = FALSE; /* assume we're getting out */ + + if (!is_pool(u.ux,u.uy)) { + if (Is_waterlevel(&u.uz)) + You("pop into an air bubble."); + else if (is_lava(u.ux, u.uy)) + You("leave the water..."); /* oops! */ + else + You("are on solid %s again.", + is_ice(u.ux, u.uy) ? "ice" : "land"); + } else if (Is_waterlevel(&u.uz)) { + still_inwater = TRUE; + } else if (Levitation) { + You("pop out of the water like a cork!"); + } else if (Flying) { + You("fly out of the water."); + } else if (Wwalking) { + You("slowly rise above the surface."); + } else { + still_inwater = TRUE; + } + if (!still_inwater) { + boolean was_underwater = (Underwater && !Is_waterlevel(&u.uz)); + + u.uinwater = 0; /* leave the water */ + if (was_underwater) { /* restore vision */ + docrt(); + vision_full_recalc = 1; + } + } } /* check for entering water or lava */ if (!u.ustuck && !Levitation && !Flying && - is_pool_or_lava(u.ux, u.uy)) { - if (u.usteed && (is_flyer(u.usteed->data) || - is_floater(u.usteed->data) || is_clinger(u.usteed->data))) { - /* floating or clinging steed keeps hero safe (is_flyer() test - is redundant; it can't be true since Flying yielded false) */ - return FALSE; - } else if (u.usteed) { - /* steed enters pool */ - dismount_steed(Underwater ? DISMOUNT_FELL : DISMOUNT_GENERIC); - /* dismount_steed() -> float_down() -> pickup() - (float_down doesn't do autopickup on Air or Water) */ - if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) return FALSE; - /* even if we actually end up at same location, float_down() - has already done spoteffect()'s trap and pickup actions */ - if (newspot) check_special_room(FALSE); /* spoteffects */ - return TRUE; - } - /* not mounted */ - - /* drown(),lava_effects() return true if hero changes - location while surviving the problem */ - if (is_lava(u.ux, u.uy)) { - if (lava_effects()) return TRUE; - } else if (!Wwalking && - (newspot || !u.uinwater || !(Swimming || Amphibious))) { - if (drown()) return TRUE; - } + is_pool_or_lava(u.ux, u.uy)) { + if (u.usteed && (is_flyer(u.usteed->data) || + is_floater(u.usteed->data) || is_clinger(u.usteed->data))) { + /* floating or clinging steed keeps hero safe (is_flyer() test + is redundant; it can't be true since Flying yielded false) */ + return FALSE; + } else if (u.usteed) { + /* steed enters pool */ + dismount_steed(Underwater ? DISMOUNT_FELL : DISMOUNT_GENERIC); + /* dismount_steed() -> float_down() -> pickup() + (float_down doesn't do autopickup on Air or Water) */ + if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) return FALSE; + /* even if we actually end up at same location, float_down() + has already done spoteffect()'s trap and pickup actions */ + if (newspot) check_special_room(FALSE); /* spoteffects */ + return TRUE; + } + /* not mounted */ + + /* drown(),lava_effects() return true if hero changes + location while surviving the problem */ + if (is_lava(u.ux, u.uy)) { + if (lava_effects()) return TRUE; + } else if (!Wwalking && + (newspot || !u.uinwater || !(Swimming || Amphibious))) { + if (drown()) return TRUE; + } } return FALSE; } @@ -1734,142 +1734,142 @@ void spoteffects(pick) boolean pick; { - static int inspoteffects = 0; - static coord spotloc; - static int spotterrain; - static struct trap *spottrap = (struct trap *)0; - static unsigned spottraptyp = NO_TRAP; - struct trap *trap = t_at(u.ux, u.uy); - register struct monst *mtmp; - - /* prevent recursion from affecting the hero all over again - [hero poly'd to iron golem enters water here, drown() inflicts - damage that triggers rehumanize() which calls spoteffects()...] */ - if (inspoteffects && u.ux == spotloc.x && u.uy == spotloc.y && - /* except when reason is transformed terrain (ice -> water) */ - spotterrain == levl[u.ux][u.uy].typ && - /* or transformed trap (land mine -> pit) */ - (!spottrap || !trap || trap->ttyp == spottraptyp)) - return; - - ++inspoteffects; - spotterrain = levl[u.ux][u.uy].typ; - spotloc.x = u.ux, spotloc.y = u.uy; - - /* moving onto different terrain might cause Levitation to toggle */ - if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0)) - switch_terrain(); - - if (pooleffects(TRUE)) goto spotdone; - - check_special_room(FALSE); - if(IS_SINK(levl[u.ux][u.uy].typ) && Levitation) - dosinkfall(); - if (!in_steed_dismounting) { /* if dismounting, we'll check again later */ - boolean pit; - - /* if levitation is due to time out at the end of this - turn, allowing it to do so could give the perception - that a trap here is being triggered twice, so adjust - the timeout to prevent that */ - if (trap && (HLevitation & TIMEOUT) == 1L && - !ELevitation && !(HLevitation & ~TIMEOUT)) { - if (rn2(2)) { /* defer timeout */ - incr_itimeout(&HLevitation, 1L); - } else { /* timeout early */ - if (float_down(I_SPECIAL|TIMEOUT, 0L)) { - /* levitation has ended; we've already triggered - any trap and [usually] performed autopickup */ - trap = 0; - pick = FALSE; - } - } - } - /* - * If not a pit, pickup before triggering trap. - * If pit, trigger trap before pickup. - */ - pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)); - if (pick && !pit) (void) pickup(1); - - if (trap) { - - /* - * dotrap on a fire trap calls melt_ice() which triggers - * spoteffects() (again) which can trigger the same fire - * trap (again). Use static spottrap to prevent that. - * We track spottraptyp because some traps morph - * (landmine to pit) and any new trap type - * should get triggered. - */ - if (!spottrap || spottraptyp != trap->ttyp) { - spottrap = trap; - spottraptyp = trap->ttyp; - dotrap(trap, 0); /* fall into arrow trap, etc. */ - spottrap = (struct trap *)0; - spottraptyp = NO_TRAP; - } - } - if (pick && pit) (void) pickup(1); - } - /* Warning alerts you to ice danger */ - if (Warning && is_ice(u.ux,u.uy)) { - static const char * const icewarnings[] = { - "The ice seems very soft and slushy.", - "You feel the ice shift beneath you!", - "The ice, is gonna BREAK!", /* The Dead Zone */ - }; - long time_left = spot_time_left(u.ux, u.uy, MELT_ICE_AWAY); - if (time_left && time_left < 15L) - pline1( - (time_left < 5L) ? icewarnings[2] : - (time_left < 10L) ? icewarnings[1] : icewarnings[0]); - } - if((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) { - mtmp->mundetected = mtmp->msleeping = 0; - switch(mtmp->data->mlet) { - case S_PIERCER: - pline("%s suddenly drops from the %s!", - Amonnam(mtmp), ceiling(u.ux,u.uy)); - if(mtmp->mtame) /* jumps to greet you, not attack */ - ; - else if(uarmh && is_metallic(uarmh)) - pline("Its blow glances off your %s.", - helm_simple_name(uarmh)); - else if (u.uac + 3 <= rnd(20)) - You("are almost hit by %s!", - x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); - else { - int dmg; - You("are hit by %s!", - x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); - dmg = d(4,6); - if(Half_physical_damage) dmg = (dmg+1) / 2; - mdamageu(mtmp, dmg); - } - break; - default: /* monster surprises you. */ - if(mtmp->mtame) - pline("%s jumps near you from the %s.", - Amonnam(mtmp), ceiling(u.ux,u.uy)); - else if(mtmp->mpeaceful) { - You("surprise %s!", - Blind && !sensemon(mtmp) ? - something : a_monnam(mtmp)); - mtmp->mpeaceful = 0; - } else - pline("%s attacks you by surprise!", - Amonnam(mtmp)); - break; - } - mnexto(mtmp); /* have to move the monster */ - } + static int inspoteffects = 0; + static coord spotloc; + static int spotterrain; + static struct trap *spottrap = (struct trap *)0; + static unsigned spottraptyp = NO_TRAP; + struct trap *trap = t_at(u.ux, u.uy); + register struct monst *mtmp; + + /* prevent recursion from affecting the hero all over again + [hero poly'd to iron golem enters water here, drown() inflicts + damage that triggers rehumanize() which calls spoteffects()...] */ + if (inspoteffects && u.ux == spotloc.x && u.uy == spotloc.y && + /* except when reason is transformed terrain (ice -> water) */ + spotterrain == levl[u.ux][u.uy].typ && + /* or transformed trap (land mine -> pit) */ + (!spottrap || !trap || trap->ttyp == spottraptyp)) + return; + + ++inspoteffects; + spotterrain = levl[u.ux][u.uy].typ; + spotloc.x = u.ux, spotloc.y = u.uy; + + /* moving onto different terrain might cause Levitation to toggle */ + if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0)) + switch_terrain(); + + if (pooleffects(TRUE)) goto spotdone; + + check_special_room(FALSE); + if(IS_SINK(levl[u.ux][u.uy].typ) && Levitation) + dosinkfall(); + if (!in_steed_dismounting) { /* if dismounting, we'll check again later */ + boolean pit; + + /* if levitation is due to time out at the end of this + turn, allowing it to do so could give the perception + that a trap here is being triggered twice, so adjust + the timeout to prevent that */ + if (trap && (HLevitation & TIMEOUT) == 1L && + !ELevitation && !(HLevitation & ~TIMEOUT)) { + if (rn2(2)) { /* defer timeout */ + incr_itimeout(&HLevitation, 1L); + } else { /* timeout early */ + if (float_down(I_SPECIAL|TIMEOUT, 0L)) { + /* levitation has ended; we've already triggered + any trap and [usually] performed autopickup */ + trap = 0; + pick = FALSE; + } + } + } + /* + * If not a pit, pickup before triggering trap. + * If pit, trigger trap before pickup. + */ + pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)); + if (pick && !pit) (void) pickup(1); + + if (trap) { + + /* + * dotrap on a fire trap calls melt_ice() which triggers + * spoteffects() (again) which can trigger the same fire + * trap (again). Use static spottrap to prevent that. + * We track spottraptyp because some traps morph + * (landmine to pit) and any new trap type + * should get triggered. + */ + if (!spottrap || spottraptyp != trap->ttyp) { + spottrap = trap; + spottraptyp = trap->ttyp; + dotrap(trap, 0); /* fall into arrow trap, etc. */ + spottrap = (struct trap *)0; + spottraptyp = NO_TRAP; + } + } + if (pick && pit) (void) pickup(1); + } + /* Warning alerts you to ice danger */ + if (Warning && is_ice(u.ux,u.uy)) { + static const char * const icewarnings[] = { + "The ice seems very soft and slushy.", + "You feel the ice shift beneath you!", + "The ice, is gonna BREAK!", /* The Dead Zone */ + }; + long time_left = spot_time_left(u.ux, u.uy, MELT_ICE_AWAY); + if (time_left && time_left < 15L) + pline1( + (time_left < 5L) ? icewarnings[2] : + (time_left < 10L) ? icewarnings[1] : icewarnings[0]); + } + if((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) { + mtmp->mundetected = mtmp->msleeping = 0; + switch(mtmp->data->mlet) { + case S_PIERCER: + pline("%s suddenly drops from the %s!", + Amonnam(mtmp), ceiling(u.ux,u.uy)); + if(mtmp->mtame) /* jumps to greet you, not attack */ + ; + else if(uarmh && is_metallic(uarmh)) + pline("Its blow glances off your %s.", + helm_simple_name(uarmh)); + else if (u.uac + 3 <= rnd(20)) + You("are almost hit by %s!", + x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); + else { + int dmg; + You("are hit by %s!", + x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); + dmg = d(4,6); + if(Half_physical_damage) dmg = (dmg+1) / 2; + mdamageu(mtmp, dmg); + } + break; + default: /* monster surprises you. */ + if(mtmp->mtame) + pline("%s jumps near you from the %s.", + Amonnam(mtmp), ceiling(u.ux,u.uy)); + else if(mtmp->mpeaceful) { + You("surprise %s!", + Blind && !sensemon(mtmp) ? + something : a_monnam(mtmp)); + mtmp->mpeaceful = 0; + } else + pline("%s attacks you by surprise!", + Amonnam(mtmp)); + break; + } + mnexto(mtmp); /* have to move the monster */ + } spotdone: - if (!--inspoteffects) { - spotterrain = STONE; /* 0 */ - spotloc.x = spotloc.y = 0; - } - return; + if (!--inspoteffects) { + spotterrain = STONE; /* 0 */ + spotloc.x = spotloc.y = 0; + } + return; } /* returns first matching monster */ @@ -1878,15 +1878,15 @@ monstinroom(mdat,roomno) struct permonst *mdat; int roomno; { - register struct monst *mtmp; - - for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - if (mtmp->data == mdat && - index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET)) - return mtmp; - } - return (struct monst *)0; + register struct monst *mtmp; + + for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (mtmp->data == mdat && + index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET)) + return mtmp; + } + return (struct monst *)0; } char * @@ -1894,67 +1894,67 @@ in_rooms(x, y, typewanted) register xchar x, y; register int typewanted; { - static char buf[5]; - char rno, *ptr = &buf[4]; - int typefound, min_x, min_y, max_x, max_y_offset, step; - register struct rm *lev; + static char buf[5]; + char rno, *ptr = &buf[4]; + int typefound, min_x, min_y, max_x, max_y_offset, step; + register struct rm *lev; #define goodtype(rno) (!typewanted || \ - ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) || \ - ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) \ - - switch (rno = levl[x][y].roomno) { - case NO_ROOM: - return(ptr); - case SHARED: - step = 2; - break; - case SHARED_PLUS: - step = 1; - break; - default: /* i.e. a regular room # */ - if (goodtype(rno)) - *(--ptr) = rno; - return(ptr); - } - - min_x = x - 1; - max_x = x + 1; - if (x < 1) - min_x += step; - else - if (x >= COLNO) - max_x -= step; - - min_y = y - 1; - max_y_offset = 2; - if (min_y < 0) { - min_y += step; - max_y_offset -= step; - } else - if ((min_y + max_y_offset) >= ROWNO) - max_y_offset -= step; - - for (x = min_x; x <= max_x; x += step) { - lev = &levl[x][min_y]; - y = 0; - if (((rno = lev[y].roomno) >= ROOMOFFSET) && - !index(ptr, rno) && goodtype(rno)) - *(--ptr) = rno; - y += step; - if (y > max_y_offset) - continue; - if (((rno = lev[y].roomno) >= ROOMOFFSET) && - !index(ptr, rno) && goodtype(rno)) - *(--ptr) = rno; - y += step; - if (y > max_y_offset) - continue; - if (((rno = lev[y].roomno) >= ROOMOFFSET) && - !index(ptr, rno) && goodtype(rno)) - *(--ptr) = rno; - } - return(ptr); + ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) || \ + ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) \ + + switch (rno = levl[x][y].roomno) { + case NO_ROOM: + return(ptr); + case SHARED: + step = 2; + break; + case SHARED_PLUS: + step = 1; + break; + default: /* i.e. a regular room # */ + if (goodtype(rno)) + *(--ptr) = rno; + return(ptr); + } + + min_x = x - 1; + max_x = x + 1; + if (x < 1) + min_x += step; + else + if (x >= COLNO) + max_x -= step; + + min_y = y - 1; + max_y_offset = 2; + if (min_y < 0) { + min_y += step; + max_y_offset -= step; + } else + if ((min_y + max_y_offset) >= ROWNO) + max_y_offset -= step; + + for (x = min_x; x <= max_x; x += step) { + lev = &levl[x][min_y]; + y = 0; + if (((rno = lev[y].roomno) >= ROOMOFFSET) && + !index(ptr, rno) && goodtype(rno)) + *(--ptr) = rno; + y += step; + if (y > max_y_offset) + continue; + if (((rno = lev[y].roomno) >= ROOMOFFSET) && + !index(ptr, rno) && goodtype(rno)) + *(--ptr) = rno; + y += step; + if (y > max_y_offset) + continue; + if (((rno = lev[y].roomno) >= ROOMOFFSET) && + !index(ptr, rno) && goodtype(rno)) + *(--ptr) = rno; + } + return(ptr); } /* is (x,y) in a town? */ @@ -1962,262 +1962,262 @@ boolean in_town(x, y) register int x, y; { - s_level *slev = Is_special(&u.uz); - register struct mkroom *sroom; - boolean has_subrooms = FALSE; - - if (!slev || !slev->flags.town) return FALSE; - - /* - * See if (x,y) is in a room with subrooms, if so, assume it's the - * town. If there are no subrooms, the whole level is in town. - */ - for (sroom = &rooms[0]; sroom->hx > 0; sroom++) { - if (sroom->nsubrooms > 0) { - has_subrooms = TRUE; - if (inside_room(sroom, x, y)) return TRUE; - } - } - - return !has_subrooms; + s_level *slev = Is_special(&u.uz); + register struct mkroom *sroom; + boolean has_subrooms = FALSE; + + if (!slev || !slev->flags.town) return FALSE; + + /* + * See if (x,y) is in a room with subrooms, if so, assume it's the + * town. If there are no subrooms, the whole level is in town. + */ + for (sroom = &rooms[0]; sroom->hx > 0; sroom++) { + if (sroom->nsubrooms > 0) { + has_subrooms = TRUE; + if (inside_room(sroom, x, y)) return TRUE; + } + } + + return !has_subrooms; } STATIC_OVL void move_update(newlev) register boolean newlev; { - char *ptr1, *ptr2, *ptr3, *ptr4; - - Strcpy(u.urooms0, u.urooms); - Strcpy(u.ushops0, u.ushops); - if (newlev) { - u.urooms[0] = '\0'; - u.uentered[0] = '\0'; - u.ushops[0] = '\0'; - u.ushops_entered[0] = '\0'; - Strcpy(u.ushops_left, u.ushops0); - return; - } - Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0)); - - for (ptr1 = &u.urooms[0], - ptr2 = &u.uentered[0], - ptr3 = &u.ushops[0], - ptr4 = &u.ushops_entered[0]; - *ptr1; ptr1++) { - if (!index(u.urooms0, *ptr1)) - *(ptr2++) = *ptr1; - if (IS_SHOP(*ptr1 - ROOMOFFSET)) { - *(ptr3++) = *ptr1; - if (!index(u.ushops0, *ptr1)) - *(ptr4++) = *ptr1; - } - } - *ptr2 = '\0'; - *ptr3 = '\0'; - *ptr4 = '\0'; - - /* filter u.ushops0 -> u.ushops_left */ - for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++) - if (!index(u.ushops, *ptr1)) - *(ptr2++) = *ptr1; - *ptr2 = '\0'; + char *ptr1, *ptr2, *ptr3, *ptr4; + + Strcpy(u.urooms0, u.urooms); + Strcpy(u.ushops0, u.ushops); + if (newlev) { + u.urooms[0] = '\0'; + u.uentered[0] = '\0'; + u.ushops[0] = '\0'; + u.ushops_entered[0] = '\0'; + Strcpy(u.ushops_left, u.ushops0); + return; + } + Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0)); + + for (ptr1 = &u.urooms[0], + ptr2 = &u.uentered[0], + ptr3 = &u.ushops[0], + ptr4 = &u.ushops_entered[0]; + *ptr1; ptr1++) { + if (!index(u.urooms0, *ptr1)) + *(ptr2++) = *ptr1; + if (IS_SHOP(*ptr1 - ROOMOFFSET)) { + *(ptr3++) = *ptr1; + if (!index(u.ushops0, *ptr1)) + *(ptr4++) = *ptr1; + } + } + *ptr2 = '\0'; + *ptr3 = '\0'; + *ptr4 = '\0'; + + /* filter u.ushops0 -> u.ushops_left */ + for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++) + if (!index(u.ushops, *ptr1)) + *(ptr2++) = *ptr1; + *ptr2 = '\0'; } void check_special_room(newlev) register boolean newlev; { - register struct monst *mtmp; - char *ptr; - - move_update(newlev); - - if (*u.ushops0) - u_left_shop(u.ushops_left, newlev); - - if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */ - return; /* no entrance messages necessary */ - - /* Did we just enter a shop? */ - if (*u.ushops_entered) - u_entered_shop(u.ushops_entered); - - for (ptr = &u.uentered[0]; *ptr; ptr++) { - int roomno = *ptr - ROOMOFFSET, - rt = rooms[roomno].rtype; - boolean msg_given = TRUE; - - /* Did we just enter some other special room? */ - /* vault.c insists that a vault remain a VAULT, - * and temples should remain TEMPLEs, - * but everything else gives a message only the first time */ - switch (rt) { - case ZOO: - pline("Welcome to David's treasure zoo!"); - break; - case SWAMP: - pline("It %s rather %s down here.", - Blind ? "feels" : "looks", - Blind ? "humid" : "muddy"); - break; - case COURT: - You("enter an opulent throne room!"); - break; - case LEPREHALL: - You("enter a leprechaun hall!"); - break; - case MORGUE: - if(midnight()) { - const char *run = locomotion(youmonst.data, "Run"); - pline("%s away! %s away!", run, run); - } else - You("have an uncanny feeling..."); - break; - case BEEHIVE: - You("enter a giant beehive!"); - break; - case COCKNEST: - You("enter a disgusting nest!"); - break; - case ANTHOLE: - You("enter an anthole!"); - break; - case BARRACKS: - if(monstinroom(&mons[PM_SOLDIER], roomno) || - monstinroom(&mons[PM_SERGEANT], roomno) || - monstinroom(&mons[PM_LIEUTENANT], roomno) || - monstinroom(&mons[PM_CAPTAIN], roomno)) - You("enter a military barracks!"); - else - You("enter an abandoned barracks."); - break; - case DELPHI: - { - struct monst *oracle = monstinroom(&mons[PM_ORACLE], - roomno); - if (oracle) { - if (!oracle->mpeaceful) - verbalize("You're in Delphi, %s.", - plname); - else - verbalize("%s, %s, welcome to Delphi!", - Hello((struct monst *) 0), plname); - } else - msg_given = FALSE; - break; - } - case TEMPLE: - intemple(roomno + ROOMOFFSET); - /*FALLTHRU*/ - default: - msg_given = (rt == TEMPLE); - rt = 0; - break; - } - if (msg_given) room_discovered(roomno); - - if (rt != 0) { - rooms[roomno].rtype = OROOM; - if (!search_special(rt)) { - /* No more room of that type */ - switch(rt) { - case COURT: - level.flags.has_court = 0; - break; - case SWAMP: - level.flags.has_swamp = 0; - break; - case MORGUE: - level.flags.has_morgue = 0; - break; - case ZOO: - level.flags.has_zoo = 0; - break; - case BARRACKS: - level.flags.has_barracks = 0; - break; - case TEMPLE: - level.flags.has_temple = 0; - break; - case BEEHIVE: - level.flags.has_beehive = 0; - break; - } - } - if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO) - for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - if (!Stealth && !rn2(3)) - mtmp->msleeping = 0; - } - } - } - - return; + register struct monst *mtmp; + char *ptr; + + move_update(newlev); + + if (*u.ushops0) + u_left_shop(u.ushops_left, newlev); + + if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */ + return; /* no entrance messages necessary */ + + /* Did we just enter a shop? */ + if (*u.ushops_entered) + u_entered_shop(u.ushops_entered); + + for (ptr = &u.uentered[0]; *ptr; ptr++) { + int roomno = *ptr - ROOMOFFSET, + rt = rooms[roomno].rtype; + boolean msg_given = TRUE; + + /* Did we just enter some other special room? */ + /* vault.c insists that a vault remain a VAULT, + * and temples should remain TEMPLEs, + * but everything else gives a message only the first time */ + switch (rt) { + case ZOO: + pline("Welcome to David's treasure zoo!"); + break; + case SWAMP: + pline("It %s rather %s down here.", + Blind ? "feels" : "looks", + Blind ? "humid" : "muddy"); + break; + case COURT: + You("enter an opulent throne room!"); + break; + case LEPREHALL: + You("enter a leprechaun hall!"); + break; + case MORGUE: + if(midnight()) { + const char *run = locomotion(youmonst.data, "Run"); + pline("%s away! %s away!", run, run); + } else + You("have an uncanny feeling..."); + break; + case BEEHIVE: + You("enter a giant beehive!"); + break; + case COCKNEST: + You("enter a disgusting nest!"); + break; + case ANTHOLE: + You("enter an anthole!"); + break; + case BARRACKS: + if(monstinroom(&mons[PM_SOLDIER], roomno) || + monstinroom(&mons[PM_SERGEANT], roomno) || + monstinroom(&mons[PM_LIEUTENANT], roomno) || + monstinroom(&mons[PM_CAPTAIN], roomno)) + You("enter a military barracks!"); + else + You("enter an abandoned barracks."); + break; + case DELPHI: + { + struct monst *oracle = monstinroom(&mons[PM_ORACLE], + roomno); + if (oracle) { + if (!oracle->mpeaceful) + verbalize("You're in Delphi, %s.", + plname); + else + verbalize("%s, %s, welcome to Delphi!", + Hello((struct monst *) 0), plname); + } else + msg_given = FALSE; + break; + } + case TEMPLE: + intemple(roomno + ROOMOFFSET); + /*FALLTHRU*/ + default: + msg_given = (rt == TEMPLE); + rt = 0; + break; + } + if (msg_given) room_discovered(roomno); + + if (rt != 0) { + rooms[roomno].rtype = OROOM; + if (!search_special(rt)) { + /* No more room of that type */ + switch(rt) { + case COURT: + level.flags.has_court = 0; + break; + case SWAMP: + level.flags.has_swamp = 0; + break; + case MORGUE: + level.flags.has_morgue = 0; + break; + case ZOO: + level.flags.has_zoo = 0; + break; + case BARRACKS: + level.flags.has_barracks = 0; + break; + case TEMPLE: + level.flags.has_temple = 0; + break; + case BEEHIVE: + level.flags.has_beehive = 0; + break; + } + } + if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO) + for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (!Stealth && !rn2(3)) + mtmp->msleeping = 0; + } + } + } + + return; } int dopickup() { - int count; - struct trap *traphere = t_at(u.ux, u.uy); - /* awful kludge to work around parse()'s pre-decrement */ - count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0; - multi = 0; /* always reset */ - /* uswallow case added by GAN 01/29/87 */ - if(u.uswallow) { - if (!u.ustuck->minvent) { - if (is_animal(u.ustuck->data)) { - You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck))); - pline("But it's kind of slimy, so you drop it."); - } else - You("don't %s anything in here to pick up.", - Blind ? "feel" : "see"); - return(1); - } else { - int tmpcount = -count; - return loot_mon(u.ustuck, &tmpcount, (boolean *)0); - } - } - if(is_pool(u.ux, u.uy)) { - if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) - || (Flying && !Breathless)) { - You("cannot dive into the water to pick things up."); - return(0); - } else if (!Underwater) { - You_cant("even see the bottom, let alone pick up %s.", - something); - return(0); - } - } - if (is_lava(u.ux, u.uy)) { - if (Wwalking || is_floater(youmonst.data) || - is_clinger(youmonst.data) || (Flying && !Breathless)) { - You_cant("reach the bottom to pick things up."); - return(0); - } else if (!likes_lava(youmonst.data)) { - You("would burn to a crisp trying to pick things up."); - return(0); - } - } - if (!OBJ_AT(u.ux, u.uy)) { - There("is nothing here to pick up."); - return 0; - } - if (!can_reach_floor(TRUE)) { - if (traphere && uteetering_at_seen_pit(traphere)) - You("cannot reach the bottom of the pit."); - else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) - rider_cant_reach(); - else if (Blind && !can_reach_floor(TRUE)) - You("cannot reach anything here."); - else - You("cannot reach the %s.", surface(u.ux,u.uy)); - return 0; - } - - return (pickup(-count)); + int count; + struct trap *traphere = t_at(u.ux, u.uy); + /* awful kludge to work around parse()'s pre-decrement */ + count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0; + multi = 0; /* always reset */ + /* uswallow case added by GAN 01/29/87 */ + if(u.uswallow) { + if (!u.ustuck->minvent) { + if (is_animal(u.ustuck->data)) { + You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck))); + pline("But it's kind of slimy, so you drop it."); + } else + You("don't %s anything in here to pick up.", + Blind ? "feel" : "see"); + return(1); + } else { + int tmpcount = -count; + return loot_mon(u.ustuck, &tmpcount, (boolean *)0); + } + } + if(is_pool(u.ux, u.uy)) { + if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) + || (Flying && !Breathless)) { + You("cannot dive into the water to pick things up."); + return(0); + } else if (!Underwater) { + You_cant("even see the bottom, let alone pick up %s.", + something); + return(0); + } + } + if (is_lava(u.ux, u.uy)) { + if (Wwalking || is_floater(youmonst.data) || + is_clinger(youmonst.data) || (Flying && !Breathless)) { + You_cant("reach the bottom to pick things up."); + return(0); + } else if (!likes_lava(youmonst.data)) { + You("would burn to a crisp trying to pick things up."); + return(0); + } + } + if (!OBJ_AT(u.ux, u.uy)) { + There("is nothing here to pick up."); + return 0; + } + if (!can_reach_floor(TRUE)) { + if (traphere && uteetering_at_seen_pit(traphere)) + You("cannot reach the bottom of the pit."); + else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) + rider_cant_reach(); + else if (Blind && !can_reach_floor(TRUE)) + You("cannot reach anything here."); + else + You("cannot reach the %s.", surface(u.ux,u.uy)); + return 0; + } + + return (pickup(-count)); } /* stop running if we see something interesting */ @@ -2234,115 +2234,115 @@ lookaround() /* Grid bugs stop if trying to move diagonal, even if blind. Maybe */ /* they polymorphed while in the middle of a long move. */ if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) { - nomul(0); - return; + nomul(0); + return; } if(Blind || context.run == 0) return; for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++) { - if(!isok(x,y)) continue; - - if(u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue; - - if(x == u.ux && y == u.uy) continue; - - if((mtmp = m_at(x,y)) && - mtmp->m_ap_type != M_AP_FURNITURE && - mtmp->m_ap_type != M_AP_OBJECT && - (!mtmp->minvis || See_invisible) && !mtmp->mundetected) { - if((context.run != 1 && !mtmp->mtame) - || (x == u.ux+u.dx && y == u.uy+u.dy)) - goto stop; - } - - if (levl[x][y].typ == STONE) continue; - if (x == u.ux-u.dx && y == u.uy-u.dy) continue; - - if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) || - IS_AIR(levl[x][y].typ)) - continue; - else if (closed_door(x,y) || - (mtmp && mtmp->m_ap_type == M_AP_FURNITURE && - (mtmp->mappearance == S_hcdoor || - mtmp->mappearance == S_vcdoor))) { - if(x != u.ux && y != u.uy) continue; - if(context.run != 1) goto stop; - goto bcorr; - } else if (levl[x][y].typ == CORR) { + if(!isok(x,y)) continue; + + if(u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue; + + if(x == u.ux && y == u.uy) continue; + + if((mtmp = m_at(x,y)) && + mtmp->m_ap_type != M_AP_FURNITURE && + mtmp->m_ap_type != M_AP_OBJECT && + (!mtmp->minvis || See_invisible) && !mtmp->mundetected) { + if((context.run != 1 && !mtmp->mtame) + || (x == u.ux+u.dx && y == u.uy+u.dy)) + goto stop; + } + + if (levl[x][y].typ == STONE) continue; + if (x == u.ux-u.dx && y == u.uy-u.dy) continue; + + if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) || + IS_AIR(levl[x][y].typ)) + continue; + else if (closed_door(x,y) || + (mtmp && mtmp->m_ap_type == M_AP_FURNITURE && + (mtmp->mappearance == S_hcdoor || + mtmp->mappearance == S_vcdoor))) { + if(x != u.ux && y != u.uy) continue; + if(context.run != 1) goto stop; + goto bcorr; + } else if (levl[x][y].typ == CORR) { bcorr: - if(levl[u.ux][u.uy].typ != ROOM) { - if(context.run == 1 || context.run == 3 || context.run == 8) { - i = dist2(x,y,u.ux+u.dx,u.uy+u.dy); - if(i > 2) continue; - if(corrct == 1 && dist2(x,y,x0,y0) != 1) - noturn = 1; - if(i < i0) { - i0 = i; - x0 = x; - y0 = y; - m0 = mtmp ? 1 : 0; - } - } - corrct++; - } - continue; - } else if ((trap = t_at(x,y)) && trap->tseen) { - if(context.run == 1) goto bcorr; /* if you must */ - if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop; - continue; - } else if (is_pool_or_lava(x,y)) { - /* water and lava only stop you if directly in front, and stop - * you even if you are running - */ - if(!Levitation && !Flying && !is_clinger(youmonst.data) && - x == u.ux+u.dx && y == u.uy+u.dy) - /* No Wwalking check; otherwise they'd be able - * to test boots by trying to SHIFT-direction - * into a pool and seeing if the game allowed it - */ - goto stop; - continue; - } else { /* e.g. objects or trap or stairs */ - if(context.run == 1) goto bcorr; - if(context.run == 8) continue; - if(mtmp) continue; /* d */ - if(((x == u.ux - u.dx) && (y != u.uy + u.dy)) || - ((y == u.uy - u.dy) && (x != u.ux + u.dx))) - continue; - } + if(levl[u.ux][u.uy].typ != ROOM) { + if(context.run == 1 || context.run == 3 || context.run == 8) { + i = dist2(x,y,u.ux+u.dx,u.uy+u.dy); + if(i > 2) continue; + if(corrct == 1 && dist2(x,y,x0,y0) != 1) + noturn = 1; + if(i < i0) { + i0 = i; + x0 = x; + y0 = y; + m0 = mtmp ? 1 : 0; + } + } + corrct++; + } + continue; + } else if ((trap = t_at(x,y)) && trap->tseen) { + if(context.run == 1) goto bcorr; /* if you must */ + if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop; + continue; + } else if (is_pool_or_lava(x,y)) { + /* water and lava only stop you if directly in front, and stop + * you even if you are running + */ + if(!Levitation && !Flying && !is_clinger(youmonst.data) && + x == u.ux+u.dx && y == u.uy+u.dy) + /* No Wwalking check; otherwise they'd be able + * to test boots by trying to SHIFT-direction + * into a pool and seeing if the game allowed it + */ + goto stop; + continue; + } else { /* e.g. objects or trap or stairs */ + if(context.run == 1) goto bcorr; + if(context.run == 8) continue; + if(mtmp) continue; /* d */ + if(((x == u.ux - u.dx) && (y != u.uy + u.dy)) || + ((y == u.uy - u.dy) && (x != u.ux + u.dx))) + continue; + } stop: - nomul(0); - return; + nomul(0); + return; } /* end for loops */ if(corrct > 1 && context.run == 2) goto stop; if((context.run == 1 || context.run == 3 || context.run == 8) && - !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) + !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) { - /* make sure that we do not turn too far */ - if(i0 == 2) { - if(u.dx == y0-u.uy && u.dy == u.ux-x0) - i = 2; /* straight turn right */ - else - i = -2; /* straight turn left */ - } else if(u.dx && u.dy) { - if((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy)) - i = -1; /* half turn left */ - else - i = 1; /* half turn right */ - } else { - if((x0-u.ux == y0-u.uy && !u.dy) || (x0-u.ux != y0-u.uy && u.dy)) - i = 1; /* half turn right */ - else - i = -1; /* half turn left */ - } - - i += u.last_str_turn; - if(i <= 2 && i >= -2) { - u.last_str_turn = i; - u.dx = x0-u.ux; - u.dy = y0-u.uy; - } + /* make sure that we do not turn too far */ + if(i0 == 2) { + if(u.dx == y0-u.uy && u.dy == u.ux-x0) + i = 2; /* straight turn right */ + else + i = -2; /* straight turn left */ + } else if(u.dx && u.dy) { + if((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy)) + i = -1; /* half turn left */ + else + i = 1; /* half turn right */ + } else { + if((x0-u.ux == y0-u.uy && !u.dy) || (x0-u.ux != y0-u.uy && u.dy)) + i = 1; /* half turn right */ + else + i = -1; /* half turn left */ + } + + i += u.last_str_turn; + if(i <= 2 && i >= -2) { + u.last_str_turn = i; + u.dx = x0-u.ux; + u.dy = y0-u.uy; + } } } @@ -2376,10 +2376,10 @@ int x, y; if (Passes_walls) return TRUE; /* or a xorn... */ /* pool could be next to a door, conceivably even inside a shop */ if (IS_DOOR(levl[x][y].typ) && (!doorless_door(x, y) || block_door(x, y))) - return FALSE; + return FALSE; /* finally, are we trying to squeeze through a too-narrow gap? */ return !(bad_rock(youmonst.data, u.ux, y) && - bad_rock(youmonst.data, x, u.uy)); + bad_rock(youmonst.data, x, u.uy)); } /* something like lookaround, but we are not running */ @@ -2387,37 +2387,37 @@ int x, y; int monster_nearby() { - register int x,y; - register struct monst *mtmp; - - /* Also see the similar check in dochugw() in monmove.c */ - for(x = u.ux-1; x <= u.ux+1; x++) - for(y = u.uy-1; y <= u.uy+1; y++) { - if(!isok(x,y)) continue; - if(x == u.ux && y == u.uy) continue; - if((mtmp = m_at(x,y)) && - mtmp->m_ap_type != M_AP_FURNITURE && - mtmp->m_ap_type != M_AP_OBJECT && - (!mtmp->mpeaceful || Hallucination) && - (!is_hider(mtmp->data) || !mtmp->mundetected) && - !noattacks(mtmp->data) && - mtmp->mcanmove && !mtmp->msleeping && /* aplvax!jcn */ - !onscary(u.ux, u.uy, mtmp) && - canspotmon(mtmp)) - return(1); - } - return(0); + register int x,y; + register struct monst *mtmp; + + /* Also see the similar check in dochugw() in monmove.c */ + for(x = u.ux-1; x <= u.ux+1; x++) + for(y = u.uy-1; y <= u.uy+1; y++) { + if(!isok(x,y)) continue; + if(x == u.ux && y == u.uy) continue; + if((mtmp = m_at(x,y)) && + mtmp->m_ap_type != M_AP_FURNITURE && + mtmp->m_ap_type != M_AP_OBJECT && + (!mtmp->mpeaceful || Hallucination) && + (!is_hider(mtmp->data) || !mtmp->mundetected) && + !noattacks(mtmp->data) && + mtmp->mcanmove && !mtmp->msleeping && /* aplvax!jcn */ + !onscary(u.ux, u.uy, mtmp) && + canspotmon(mtmp)) + return(1); + } + return(0); } void nomul(nval) - register int nval; + register int nval; { - if(multi < nval) return; /* This is a bug fix by ab@unido */ - u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */ - u.usleep = 0; - multi = nval; - context.travel = context.travel1 = context.mv = context.run = 0; + if(multi < nval) return; /* This is a bug fix by ab@unido */ + u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */ + u.usleep = 0; + multi = nval; + context.travel = context.travel1 = context.mv = context.run = 0; } /* called when a non-movement, multi-turn action has completed */ @@ -2425,44 +2425,44 @@ void unmul(msg_override) const char *msg_override; { - multi = 0; /* caller will usually have done this already */ - if (msg_override) nomovemsg = msg_override; - else if (!nomovemsg) nomovemsg = You_can_move_again; - if (*nomovemsg) pline1(nomovemsg); - nomovemsg = 0; - u.usleep = 0; - if (afternmv) (*afternmv)(); - afternmv = 0; + multi = 0; /* caller will usually have done this already */ + if (msg_override) nomovemsg = msg_override; + else if (!nomovemsg) nomovemsg = You_can_move_again; + if (*nomovemsg) pline1(nomovemsg); + nomovemsg = 0; + u.usleep = 0; + if (afternmv) (*afternmv)(); + afternmv = 0; } STATIC_OVL void maybe_wail() { static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES, - SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES, - TELEPORT_CONTROL, STEALTH, FAST, INVIS }; + SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES, + TELEPORT_CONTROL, STEALTH, FAST, INVIS }; if (moves <= wailmsg + 50) return; wailmsg = moves; if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) { - const char *who; - int i, powercnt; - - who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? - urole.name.m : "Elf"; - if (u.uhp == 1) { - pline("%s is about to die.", who); - } else { - for (i = 0, powercnt = 0; i < SIZE(powers); ++i) - if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt; - - pline(powercnt >= 4 ? "%s, all your powers will be lost..." - : "%s, your life force is running out.", who); - } + const char *who; + int i, powercnt; + + who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? + urole.name.m : "Elf"; + if (u.uhp == 1) { + pline("%s is about to die.", who); } else { - You_hear(u.uhp == 1 ? "the wailing of the Banshee..." - : "the howling of the CwnAnnwn..."); + for (i = 0, powercnt = 0; i < SIZE(powers); ++i) + if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt; + + pline(powercnt >= 4 ? "%s, all your powers will be lost..." + : "%s, your life force is running out.", who); + } + } else { + You_hear(u.uhp == 1 ? "the wailing of the Banshee..." + : "the howling of the CwnAnnwn..."); } } @@ -2472,62 +2472,62 @@ register int n; register const char *knam; boolean k_format; { - if (Upolyd) { - u.mh -= n; - if (u.mhmax < u.mh) u.mhmax = u.mh; - context.botl = 1; - if (u.mh < 1) - rehumanize(); - else if (n > 0 && u.mh*10 < u.mhmax && Unchanging) - maybe_wail(); - return; - } - - u.uhp -= n; - if(u.uhp > u.uhpmax) - u.uhpmax = u.uhp; /* perhaps n was negative */ - context.botl = 1; - if(u.uhp < 1) { - killer.format = k_format; - if (killer.name != knam) /* the thing that killed you */ - Strcpy(killer.name, knam ? knam : ""); - You("die..."); - done(DIED); - } else if (n > 0 && u.uhp*10 < u.uhpmax) { - maybe_wail(); - } + if (Upolyd) { + u.mh -= n; + if (u.mhmax < u.mh) u.mhmax = u.mh; + context.botl = 1; + if (u.mh < 1) + rehumanize(); + else if (n > 0 && u.mh*10 < u.mhmax && Unchanging) + maybe_wail(); + return; + } + + u.uhp -= n; + if(u.uhp > u.uhpmax) + u.uhpmax = u.uhp; /* perhaps n was negative */ + context.botl = 1; + if(u.uhp < 1) { + killer.format = k_format; + if (killer.name != knam) /* the thing that killed you */ + Strcpy(killer.name, knam ? knam : ""); + You("die..."); + done(DIED); + } else if (n > 0 && u.uhp*10 < u.uhpmax) { + maybe_wail(); + } } int weight_cap() { - register long carrcap; - - carrcap = 25*(ACURRSTR + ACURR(A_CON)) + 50; - if (Upolyd) { - /* consistent with can_carry() in mon.c */ - if (youmonst.data->mlet == S_NYMPH) - carrcap = MAX_CARR_CAP; - else if (!youmonst.data->cwt) - carrcap = (carrcap * (long)youmonst.data->msize) / MZ_HUMAN; - else if (!strongmonst(youmonst.data) - || (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN))) - carrcap = (carrcap * (long)youmonst.data->cwt / WT_HUMAN); - } - - if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */ - || (u.usteed && strongmonst(u.usteed->data)) - ) - carrcap = MAX_CARR_CAP; - else { - if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP; - if (!Flying) { - if(EWounded_legs & LEFT_SIDE) carrcap -= 100; - if(EWounded_legs & RIGHT_SIDE) carrcap -= 100; - } - if (carrcap < 0) carrcap = 0; - } - return((int) carrcap); + register long carrcap; + + carrcap = 25*(ACURRSTR + ACURR(A_CON)) + 50; + if (Upolyd) { + /* consistent with can_carry() in mon.c */ + if (youmonst.data->mlet == S_NYMPH) + carrcap = MAX_CARR_CAP; + else if (!youmonst.data->cwt) + carrcap = (carrcap * (long)youmonst.data->msize) / MZ_HUMAN; + else if (!strongmonst(youmonst.data) + || (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN))) + carrcap = (carrcap * (long)youmonst.data->cwt / WT_HUMAN); + } + + if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */ + || (u.usteed && strongmonst(u.usteed->data)) + ) + carrcap = MAX_CARR_CAP; + else { + if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP; + if (!Flying) { + if(EWounded_legs & LEFT_SIDE) carrcap -= 100; + if(EWounded_legs & RIGHT_SIDE) carrcap -= 100; + } + if (carrcap < 0) carrcap = 0; + } + return((int) carrcap); } static int wc; /* current weight_cap(); valid after call to inv_weight() */ @@ -2537,18 +2537,18 @@ static int wc; /* current weight_cap(); valid after call to inv_weight() */ int inv_weight() { - register struct obj *otmp = invent; - register int wt = 0; - - while (otmp) { - if (otmp->oclass == COIN_CLASS) - wt += (int)(((long)otmp->quan + 50L) / 100L); - else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data)) - wt += otmp->owt; - otmp = otmp->nobj; - } - wc = weight_cap(); - return (wt - wc); + register struct obj *otmp = invent; + register int wt = 0; + + while (otmp) { + if (otmp->oclass == COIN_CLASS) + wt += (int)(((long)otmp->quan + 50L) / 100L); + else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data)) + wt += otmp->owt; + otmp = otmp->nobj; + } + wc = weight_cap(); + return (wt - wc); } /* @@ -2586,11 +2586,11 @@ check_capacity(str) const char *str; { if(near_capacity() >= EXT_ENCUMBER) { - if(str) - pline1(str); - else - You_cant("do that while carrying so much stuff."); - return 1; + if(str) + pline1(str); + else + You_cant("do that while carrying so much stuff."); + return 1; } return 0; } @@ -2599,14 +2599,14 @@ int inv_cnt(incl_gold) boolean incl_gold; { - register struct obj *otmp = invent; - register int ct = 0; - - while(otmp){ - if (incl_gold || otmp->invlet != GOLD_SYM) ct++; - otmp = otmp->nobj; - } - return(ct); + register struct obj *otmp = invent; + register int ct = 0; + + while(otmp){ + if (incl_gold || otmp->invlet != GOLD_SYM) ct++; + otmp = otmp->nobj; + } + return(ct); } /* Counts the money in an object chain. */ @@ -2618,9 +2618,9 @@ money_cnt(otmp) struct obj *otmp; { while (otmp) { - /* Must change when silver & copper is implemented: */ - if (otmp->oclass == COIN_CLASS) return otmp->quan; - otmp = otmp->nobj; + /* Must change when silver & copper is implemented: */ + if (otmp->oclass == COIN_CLASS) return otmp->quan; + otmp = otmp->nobj; } return 0L; } diff --git a/src/invent.c b/src/invent.c index 62295915c..37b1a1549 100644 --- a/src/invent.c +++ b/src/invent.c @@ -46,33 +46,33 @@ void assigninvlet(otmp) register struct obj *otmp; { - boolean inuse[52]; - register int i; - register struct obj *obj; - - /* there should be at most one of these in inventory... */ - if (otmp->oclass == COIN_CLASS) { - otmp->invlet = GOLD_SYM; - return; - } - - for(i = 0; i < 52; i++) inuse[i] = FALSE; - for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) { - i = obj->invlet; - if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else - if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE; - if(i == otmp->invlet) otmp->invlet = 0; - } - if((i = otmp->invlet) && - (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z'))) - return; - for(i = lastinvnr+1; i != lastinvnr; i++) { - if(i == 52) { i = -1; continue; } - if(!inuse[i]) break; - } - otmp->invlet = (inuse[i] ? NOINVSYM : - (i < 26) ? ('a'+i) : ('A'+i-26)); - lastinvnr = i; + boolean inuse[52]; + register int i; + register struct obj *obj; + + /* there should be at most one of these in inventory... */ + if (otmp->oclass == COIN_CLASS) { + otmp->invlet = GOLD_SYM; + return; + } + + for(i = 0; i < 52; i++) inuse[i] = FALSE; + for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) { + i = obj->invlet; + if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else + if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE; + if(i == otmp->invlet) otmp->invlet = 0; + } + if((i = otmp->invlet) && + (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z'))) + return; + for(i = lastinvnr+1; i != lastinvnr; i++) { + if(i == 52) { i = -1; continue; } + if(!inuse[i]) break; + } + otmp->invlet = (inuse[i] ? NOINVSYM : + (i < 26) ? ('a'+i) : ('A'+i-26)); + lastinvnr = i; } /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */ @@ -82,30 +82,30 @@ register struct obj *otmp; STATIC_OVL void reorder_invent() { - struct obj *otmp, *prev, *next; - boolean need_more_sorting; - - do { - /* - * We expect at most one item to be out of order, so this - * isn't nearly as inefficient as it may first appear. - */ - need_more_sorting = FALSE; - for (otmp = invent, prev = 0; otmp; ) { - next = otmp->nobj; - if (next && inv_rank(next) < inv_rank(otmp)) { - need_more_sorting = TRUE; - if (prev) prev->nobj = next; - else invent = next; - otmp->nobj = next->nobj; - next->nobj = otmp; - prev = next; - } else { - prev = otmp; - otmp = next; - } - } - } while (need_more_sorting); + struct obj *otmp, *prev, *next; + boolean need_more_sorting; + + do { + /* + * We expect at most one item to be out of order, so this + * isn't nearly as inefficient as it may first appear. + */ + need_more_sorting = FALSE; + for (otmp = invent, prev = 0; otmp; ) { + next = otmp->nobj; + if (next && inv_rank(next) < inv_rank(otmp)) { + need_more_sorting = TRUE; + if (prev) prev->nobj = next; + else invent = next; + otmp->nobj = next->nobj; + next->nobj = otmp; + prev = next; + } else { + prev = otmp; + otmp = next; + } + } + } while (need_more_sorting); } #undef inv_rank @@ -117,33 +117,33 @@ struct obj * merge_choice(objlist, obj) struct obj *objlist, *obj; { - struct monst *shkp; - int save_nocharge; - - if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */ - return (struct obj *)0; - /* if this is an item on the shop floor, the attributes it will - have when carried are different from what they are now; prevent - that from eliciting an incorrect result from mergable() */ - save_nocharge = obj->no_charge; - if (objlist == invent && obj->where == OBJ_FLOOR && - (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) { - if (obj->no_charge) obj->no_charge = 0; - /* A billable object won't have its `unpaid' bit set, so would - erroneously seem to be a candidate to merge with a similar - ordinary object. That's no good, because once it's really - picked up, it won't merge after all. It might merge with - another unpaid object, but we can't check that here (depends - too much upon shk's bill) and if it doesn't merge it would - end up in the '#' overflow inventory slot, so reject it now. */ - else if (inhishop(shkp)) return (struct obj *)0; - } - while (objlist) { - if (mergable(objlist, obj)) break; - objlist = objlist->nobj; - } - obj->no_charge = save_nocharge; - return objlist; + struct monst *shkp; + int save_nocharge; + + if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */ + return (struct obj *)0; + /* if this is an item on the shop floor, the attributes it will + have when carried are different from what they are now; prevent + that from eliciting an incorrect result from mergable() */ + save_nocharge = obj->no_charge; + if (objlist == invent && obj->where == OBJ_FLOOR && + (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) { + if (obj->no_charge) obj->no_charge = 0; + /* A billable object won't have its `unpaid' bit set, so would + erroneously seem to be a candidate to merge with a similar + ordinary object. That's no good, because once it's really + picked up, it won't merge after all. It might merge with + another unpaid object, but we can't check that here (depends + too much upon shk's bill) and if it doesn't merge it would + end up in the '#' overflow inventory slot, so reject it now. */ + else if (inhishop(shkp)) return (struct obj *)0; + } + while (objlist) { + if (mergable(objlist, obj)) break; + objlist = objlist->nobj; + } + obj->no_charge = save_nocharge; + return objlist; } /* merge obj with otmp and delete obj if types agree */ @@ -151,73 +151,73 @@ int merged(potmp, pobj) struct obj **potmp, **pobj; { - register struct obj *otmp = *potmp, *obj = *pobj; - - if(mergable(otmp, obj)) { - /* Approximate age: we do it this way because if we were to - * do it "accurately" (merge only when ages are identical) - * we'd wind up never merging any corpses. - * otmp->age = otmp->age*(1-proportion) + obj->age*proportion; - * - * Don't do the age manipulation if lit. We would need - * to stop the burn on both items, then merge the age, - * then restart the burn. - */ - if (!obj->lamplit) - otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan)) - / (otmp->quan + obj->quan); - - otmp->quan += obj->quan; + register struct obj *otmp = *potmp, *obj = *pobj; + + if(mergable(otmp, obj)) { + /* Approximate age: we do it this way because if we were to + * do it "accurately" (merge only when ages are identical) + * we'd wind up never merging any corpses. + * otmp->age = otmp->age*(1-proportion) + obj->age*proportion; + * + * Don't do the age manipulation if lit. We would need + * to stop the burn on both items, then merge the age, + * then restart the burn. + */ + if (!obj->lamplit) + otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan)) + / (otmp->quan + obj->quan); + + otmp->quan += obj->quan; /* temporary special case for gold objects!!!! */ - if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp); - else otmp->owt += obj->owt; - if(!has_oname(otmp) && has_oname(obj)) - otmp = *potmp = oname(otmp, ONAME(obj)); - obj_extract_self(obj); - - /* really should merge the timeouts */ - if (obj->lamplit) obj_merge_light_sources(obj, otmp); - if (obj->timed) obj_stop_timers(obj); /* follows lights */ - - /* fixup for `#adjust' merging wielded darts, daggers, &c */ - if (obj->owornmask && carried(otmp)) { - long wmask = otmp->owornmask | obj->owornmask; - - /* Both the items might be worn in competing slots; - merger preference (regardless of which is which): - primary weapon + alternate weapon -> primary weapon; - primary weapon + quiver -> primary weapon; - alternate weapon + quiver -> alternate weapon. - (Prior to 3.3.0, it was not possible for the two - stacks to be worn in different slots and `obj' - didn't need to be unworn when merging.) */ - if (wmask & W_WEP) wmask = W_WEP; - else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP; - else if (wmask & W_QUIVER) wmask = W_QUIVER; - else { - impossible("merging strangely worn items (%lx)", wmask); - wmask = otmp->owornmask; - } - if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp); - setworn(otmp, wmask); - setnotworn(obj); - } + if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp); + else otmp->owt += obj->owt; + if(!has_oname(otmp) && has_oname(obj)) + otmp = *potmp = oname(otmp, ONAME(obj)); + obj_extract_self(obj); + + /* really should merge the timeouts */ + if (obj->lamplit) obj_merge_light_sources(obj, otmp); + if (obj->timed) obj_stop_timers(obj); /* follows lights */ + + /* fixup for `#adjust' merging wielded darts, daggers, &c */ + if (obj->owornmask && carried(otmp)) { + long wmask = otmp->owornmask | obj->owornmask; + + /* Both the items might be worn in competing slots; + merger preference (regardless of which is which): + primary weapon + alternate weapon -> primary weapon; + primary weapon + quiver -> primary weapon; + alternate weapon + quiver -> alternate weapon. + (Prior to 3.3.0, it was not possible for the two + stacks to be worn in different slots and `obj' + didn't need to be unworn when merging.) */ + if (wmask & W_WEP) wmask = W_WEP; + else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP; + else if (wmask & W_QUIVER) wmask = W_QUIVER; + else { + impossible("merging strangely worn items (%lx)", wmask); + wmask = otmp->owornmask; + } + if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp); + setworn(otmp, wmask); + setnotworn(obj); + } #if 0 - /* (this should not be necessary, since items - already in a monster's inventory don't ever get - merged into other objects [only vice versa]) */ - else if (obj->owornmask && mcarried(otmp)) { - if (obj == MON_WEP(otmp->ocarry)) { - MON_WEP(otmp->ocarry) = otmp; - otmp->owornmask = W_WEP; - } - } + /* (this should not be necessary, since items + already in a monster's inventory don't ever get + merged into other objects [only vice versa]) */ + else if (obj->owornmask && mcarried(otmp)) { + if (obj == MON_WEP(otmp->ocarry)) { + MON_WEP(otmp->ocarry) = otmp; + otmp->owornmask = W_WEP; + } + } #endif /*0*/ - obfree(obj,otmp); /* free(obj), bill->otmp */ - return(1); - } - return 0; + obfree(obj,otmp); /* free(obj), bill->otmp */ + return(1); + } + return 0; } /* @@ -235,29 +235,29 @@ void addinv_core1(obj) struct obj *obj; { - if (obj->oclass == COIN_CLASS) { - context.botl = 1; - } else if (obj->otyp == AMULET_OF_YENDOR) { - if (u.uhave.amulet) impossible("already have amulet?"); - u.uhave.amulet = 1; - } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { - if (u.uhave.menorah) impossible("already have candelabrum?"); - u.uhave.menorah = 1; - } else if (obj->otyp == BELL_OF_OPENING) { - if (u.uhave.bell) impossible("already have silver bell?"); - u.uhave.bell = 1; - } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { - if (u.uhave.book) impossible("already have the book?"); - u.uhave.book = 1; - } else if (obj->oartifact) { - if (is_quest_artifact(obj)) { - if (u.uhave.questart) - impossible("already have quest artifact?"); - u.uhave.questart = 1; - artitouch(obj); - } - set_artifact_intrinsic(obj, 1, W_ART); - } + if (obj->oclass == COIN_CLASS) { + context.botl = 1; + } else if (obj->otyp == AMULET_OF_YENDOR) { + if (u.uhave.amulet) impossible("already have amulet?"); + u.uhave.amulet = 1; + } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { + if (u.uhave.menorah) impossible("already have candelabrum?"); + u.uhave.menorah = 1; + } else if (obj->otyp == BELL_OF_OPENING) { + if (u.uhave.bell) impossible("already have silver bell?"); + u.uhave.bell = 1; + } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { + if (u.uhave.book) impossible("already have the book?"); + u.uhave.book = 1; + } else if (obj->oartifact) { + if (is_quest_artifact(obj)) { + if (u.uhave.questart) + impossible("already have quest artifact?"); + u.uhave.questart = 1; + artitouch(obj); + } + set_artifact_intrinsic(obj, 1, W_ART); + } } /* @@ -273,11 +273,11 @@ void addinv_core2(obj) struct obj *obj; { - if (confers_luck(obj)) { - /* new luckstone must be in inventory by this point - * for correct calculation */ - set_moreluck(); - } + if (confers_luck(obj)) { + /* new luckstone must be in inventory by this point + * for correct calculation */ + set_moreluck(); + } } /* @@ -288,48 +288,60 @@ struct obj * addinv(obj) struct obj *obj; { - struct obj *otmp, *prev; - - if (obj->where != OBJ_FREE) - panic("addinv: obj not free"); - /* normally addtobill() clears no_charge when items in a shop are - picked up, but won't do so if the shop has become untended */ - obj->no_charge = 0; /* should not be set in hero's invent */ - if (Has_contents(obj)) picked_container(obj); /* clear no_charge */ - obj->was_thrown = 0; /* not meaningful for invent */ - - addinv_core1(obj); - - /* merge with quiver in preference to any other inventory slot - in case quiver and wielded weapon are both eligible; adding - extra to quivered stack is more useful than to wielded one */ - if (uquiver && merged(&uquiver, &obj)) { - obj = uquiver; - goto added; - } - /* merge if possible; find end of chain in the process */ - for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj) - if (merged(&otmp, &obj)) { - obj = otmp; - goto added; - } - /* didn't merge, so insert into chain */ - if (flags.invlet_constant || !prev) { - if (flags.invlet_constant) assigninvlet(obj); - obj->nobj = invent; /* insert at beginning */ - invent = obj; - if (flags.invlet_constant) reorder_invent(); - } else { - prev->nobj = obj; /* insert at end */ - obj->nobj = 0; - } - obj->where = OBJ_INVENT; + struct obj *otmp, *prev; + + if (obj->where != OBJ_FREE) + panic("addinv: obj not free"); + /* normally addtobill() clears no_charge when items in a shop are + picked up, but won't do so if the shop has become untended */ + obj->no_charge = 0; /* should not be set in hero's invent */ + if (Has_contents(obj)) picked_container(obj); /* clear no_charge */ + obj->was_thrown = 0; /* not meaningful for invent */ + + addinv_core1(obj); + + /* we want globby things to become one big glob whereever possible + so we need to trigger this before merged() is called */ + if (obj->globby && merge_choice(invent, obj)) { + for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj) { + if (otmp->otyp == obj->otyp) { + pline("The %s coalesce.", makeplural(obj_typename(obj->otyp))); + obj = obj_meld(&otmp, &obj); + goto added; + } + } + } + + /* merge with quiver in preference to any other inventory slot + in case quiver and wielded weapon are both eligible; adding + extra to quivered stack is more useful than to wielded one */ + if (uquiver && merged(&uquiver, &obj)) { + obj = uquiver; + goto added; + } + /* merge if possible; find end of chain in the process */ + for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj) + if (merged(&otmp, &obj)) { + obj = otmp; + goto added; + } + /* didn't merge, so insert into chain */ + if (flags.invlet_constant || !prev) { + if (flags.invlet_constant) assigninvlet(obj); + obj->nobj = invent; /* insert at beginning */ + invent = obj; + if (flags.invlet_constant) reorder_invent(); + } else { + prev->nobj = obj; /* insert at end */ + obj->nobj = 0; + } + obj->where = OBJ_INVENT; added: - addinv_core2(obj); - carry_obj_effects(obj); /* carrying affects the obj */ - update_inventory(); - return(obj); + addinv_core2(obj); + carry_obj_effects(obj); /* carrying affects the obj */ + update_inventory(); + return(obj); } /* @@ -342,15 +354,15 @@ void carry_obj_effects(obj) struct obj *obj; { - /* Cursed figurines can spontaneously transform - when carried. */ - if (obj->otyp == FIGURINE) { - if (obj->cursed - && obj->corpsenm != NON_PM - && !dead_species(obj->corpsenm,TRUE)) { - attach_fig_transform_timeout(obj); - } - } + /* Cursed figurines can spontaneously transform + when carried. */ + if (obj->otyp == FIGURINE) { + if (obj->cursed + && obj->corpsenm != NON_PM + && !dead_species(obj->corpsenm,TRUE)) { + attach_fig_transform_timeout(obj); + } + } } /* Add an item to the inventory unless we're fumbling or it refuses to be @@ -365,67 +377,67 @@ hold_another_object(obj, drop_fmt, drop_arg, hold_msg) struct obj *obj; const char *drop_fmt, *drop_arg, *hold_msg; { - char buf[BUFSZ]; - - if (!Blind) obj->dknown = 1; /* maximize mergibility */ - if (obj->oartifact) { - /* place_object may change these */ - boolean crysknife = (obj->otyp == CRYSKNIFE); - int oerode = obj->oerodeproof; - boolean wasUpolyd = Upolyd; - - /* in case touching this object turns out to be fatal */ - place_object(obj, u.ux, u.uy); - - if (!touch_artifact(obj, &youmonst)) { - obj_extract_self(obj); /* remove it from the floor */ - dropy(obj); /* now put it back again :-) */ - return obj; - } else if (wasUpolyd && !Upolyd) { - /* loose your grip if you revert your form */ - if (drop_fmt) pline(drop_fmt, drop_arg); - obj_extract_self(obj); - dropy(obj); - return obj; - } - obj_extract_self(obj); - if (crysknife) { - obj->otyp = CRYSKNIFE; - obj->oerodeproof = oerode; - } - } - if (Fumbling) { - if (drop_fmt) pline(drop_fmt, drop_arg); - dropy(obj); - } else { - long oquan = obj->quan; - int prev_encumbr = near_capacity(); /* before addinv() */ - - /* encumbrance only matters if it would now become worse - than max( current_value, stressed ) */ - if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER; - /* addinv() may redraw the entire inventory, overwriting - drop_arg when it comes from something like doname() */ - if (drop_arg) drop_arg = strcpy(buf, drop_arg); - - obj = addinv(obj); - if (inv_cnt(FALSE) > 52 - || ((obj->otyp != LOADSTONE || !obj->cursed) - && near_capacity() > prev_encumbr)) { - if (drop_fmt) pline(drop_fmt, drop_arg); - /* undo any merge which took place */ - if (obj->quan > oquan) obj = splitobj(obj, oquan); - dropx(obj); - } else { - if (flags.autoquiver && !uquiver && !obj->owornmask && - (is_missile(obj) || - ammo_and_launcher(obj, uwep) || - ammo_and_launcher(obj, uswapwep))) - setuqwep(obj); - if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan); - } - } - return obj; + char buf[BUFSZ]; + + if (!Blind) obj->dknown = 1; /* maximize mergibility */ + if (obj->oartifact) { + /* place_object may change these */ + boolean crysknife = (obj->otyp == CRYSKNIFE); + int oerode = obj->oerodeproof; + boolean wasUpolyd = Upolyd; + + /* in case touching this object turns out to be fatal */ + place_object(obj, u.ux, u.uy); + + if (!touch_artifact(obj, &youmonst)) { + obj_extract_self(obj); /* remove it from the floor */ + dropy(obj); /* now put it back again :-) */ + return obj; + } else if (wasUpolyd && !Upolyd) { + /* loose your grip if you revert your form */ + if (drop_fmt) pline(drop_fmt, drop_arg); + obj_extract_self(obj); + dropy(obj); + return obj; + } + obj_extract_self(obj); + if (crysknife) { + obj->otyp = CRYSKNIFE; + obj->oerodeproof = oerode; + } + } + if (Fumbling) { + if (drop_fmt) pline(drop_fmt, drop_arg); + dropy(obj); + } else { + long oquan = obj->quan; + int prev_encumbr = near_capacity(); /* before addinv() */ + + /* encumbrance only matters if it would now become worse + than max( current_value, stressed ) */ + if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER; + /* addinv() may redraw the entire inventory, overwriting + drop_arg when it comes from something like doname() */ + if (drop_arg) drop_arg = strcpy(buf, drop_arg); + + obj = addinv(obj); + if (inv_cnt(FALSE) > 52 + || ((obj->otyp != LOADSTONE || !obj->cursed) + && near_capacity() > prev_encumbr)) { + if (drop_fmt) pline(drop_fmt, drop_arg); + /* undo any merge which took place */ + if (obj->quan > oquan) obj = splitobj(obj, oquan); + dropx(obj); + } else { + if (flags.autoquiver && !uquiver && !obj->owornmask && + (is_missile(obj) || + ammo_and_launcher(obj, uwep) || + ammo_and_launcher(obj, uswapwep))) + setuqwep(obj); + if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan); + } + } + return obj; } /* useup() all of an item regardless of its quantity */ @@ -433,25 +445,25 @@ void useupall(obj) struct obj *obj; { - setnotworn(obj); - freeinv(obj); - obfree(obj, (struct obj *)0); /* deletes contents also */ + setnotworn(obj); + freeinv(obj); + obfree(obj, (struct obj *)0); /* deletes contents also */ } void useup(obj) register struct obj *obj; { - /* Note: This works correctly for containers because they */ - /* (containers) don't merge. */ - if (obj->quan > 1L) { - obj->in_use = FALSE; /* no longer in use */ - obj->quan--; - obj->owt = weight(obj); - update_inventory(); - } else { - useupall(obj); - } + /* Note: This works correctly for containers because they */ + /* (containers) don't merge. */ + if (obj->quan > 1L) { + obj->in_use = FALSE; /* no longer in use */ + obj->quan--; + obj->owt = weight(obj); + update_inventory(); + } else { + useupall(obj); + } } /* use one charge from an item and possibly incur shop debt for it */ @@ -460,9 +472,9 @@ consume_obj_charge(obj, maybe_unpaid) struct obj *obj; boolean maybe_unpaid; /* false if caller handles shop billing */ { - if (maybe_unpaid) check_unpaid(obj); - obj->spe -= 1; - if (obj->known) update_inventory(); + if (maybe_unpaid) check_unpaid(obj); + obj->spe -= 1; + if (obj->known) update_inventory(); } /* @@ -476,38 +488,38 @@ void freeinv_core(obj) struct obj *obj; { - if (obj->oclass == COIN_CLASS) { - context.botl = 1; - return; - } else if (obj->otyp == AMULET_OF_YENDOR) { - if (!u.uhave.amulet) impossible("don't have amulet?"); - u.uhave.amulet = 0; - } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { - if (!u.uhave.menorah) impossible("don't have candelabrum?"); - u.uhave.menorah = 0; - } else if (obj->otyp == BELL_OF_OPENING) { - if (!u.uhave.bell) impossible("don't have silver bell?"); - u.uhave.bell = 0; - } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { - if (!u.uhave.book) impossible("don't have the book?"); - u.uhave.book = 0; - } else if (obj->oartifact) { - if (is_quest_artifact(obj)) { - if (!u.uhave.questart) - impossible("don't have quest artifact?"); - u.uhave.questart = 0; - } - set_artifact_intrinsic(obj, 0, W_ART); - } - - if (obj->otyp == LOADSTONE) { - curse(obj); - } else if (confers_luck(obj)) { - set_moreluck(); - context.botl = 1; - } else if (obj->otyp == FIGURINE && obj->timed) { - (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj)); - } + if (obj->oclass == COIN_CLASS) { + context.botl = 1; + return; + } else if (obj->otyp == AMULET_OF_YENDOR) { + if (!u.uhave.amulet) impossible("don't have amulet?"); + u.uhave.amulet = 0; + } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { + if (!u.uhave.menorah) impossible("don't have candelabrum?"); + u.uhave.menorah = 0; + } else if (obj->otyp == BELL_OF_OPENING) { + if (!u.uhave.bell) impossible("don't have silver bell?"); + u.uhave.bell = 0; + } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { + if (!u.uhave.book) impossible("don't have the book?"); + u.uhave.book = 0; + } else if (obj->oartifact) { + if (is_quest_artifact(obj)) { + if (!u.uhave.questart) + impossible("don't have quest artifact?"); + u.uhave.questart = 0; + } + set_artifact_intrinsic(obj, 0, W_ART); + } + + if (obj->otyp == LOADSTONE) { + curse(obj); + } else if (confers_luck(obj)) { + set_moreluck(); + context.botl = 1; + } else if (obj->otyp == FIGURINE && obj->timed) { + (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj)); + } } /* remove an object from the hero's inventory */ @@ -515,26 +527,26 @@ void freeinv(obj) register struct obj *obj; { - extract_nobj(obj, &invent); - freeinv_core(obj); - update_inventory(); + extract_nobj(obj, &invent); + freeinv_core(obj); + update_inventory(); } void delallobj(x, y) int x, y; { - struct obj *otmp, *otmp2; + struct obj *otmp, *otmp2; - for (otmp = level.objects[x][y]; otmp; otmp = otmp2) { - if (otmp == uball) - unpunish(); - /* after unpunish(), or might get deallocated chain */ - otmp2 = otmp->nexthere; - if (otmp == uchain) - continue; - delobj(otmp); - } + for (otmp = level.objects[x][y]; otmp; otmp = otmp2) { + if (otmp == uball) + unpunish(); + /* after unpunish(), or might get deallocated chain */ + otmp2 = otmp->nexthere; + if (otmp == uchain) + continue; + delobj(otmp); + } } /* destroy object in fobj chain (if unpaid, it remains on the bill) */ @@ -542,23 +554,23 @@ void delobj(obj) register struct obj *obj; { - boolean update_map; - - if (obj->otyp == AMULET_OF_YENDOR || - obj->otyp == CANDELABRUM_OF_INVOCATION || - obj->otyp == BELL_OF_OPENING || - obj->otyp == SPE_BOOK_OF_THE_DEAD) { - /* player might be doing something stupid, but we - * can't guarantee that. assume special artifacts - * are indestructible via drawbridges, and exploding - * chests, and golem creation, and ... - */ - return; - } - update_map = (obj->where == OBJ_FLOOR); - obj_extract_self(obj); - if (update_map) newsym(obj->ox, obj->oy); - obfree(obj, (struct obj *) 0); /* frees contents also */ + boolean update_map; + + if (obj->otyp == AMULET_OF_YENDOR || + obj->otyp == CANDELABRUM_OF_INVOCATION || + obj->otyp == BELL_OF_OPENING || + obj->otyp == SPE_BOOK_OF_THE_DEAD) { + /* player might be doing something stupid, but we + * can't guarantee that. assume special artifacts + * are indestructible via drawbridges, and exploding + * chests, and golem creation, and ... + */ + return; + } + update_map = (obj->where == OBJ_FLOOR); + obj_extract_self(obj); + if (update_map) newsym(obj->ox, obj->oy); + obfree(obj, (struct obj *) 0); /* frees contents also */ } /* try to find a particular type of object at designated map location */ @@ -567,12 +579,12 @@ sobj_at(otyp, x, y) int otyp; int x, y; { - register struct obj *otmp; + register struct obj *otmp; - for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) - if (otmp->otyp == otyp) break; + for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) + if (otmp->otyp == otyp) break; - return otmp; + return otmp; } /* sobj_at(&c) traversal -- find next object of specified type */ @@ -582,46 +594,46 @@ struct obj *obj; int type; boolean by_nexthere; { - register struct obj *otmp; + register struct obj *otmp; - otmp = obj; /* start with the object after this one */ - do { - otmp = !by_nexthere ? otmp->nobj : otmp->nexthere; - if (!otmp) break; - } while (otmp->otyp != type); + otmp = obj; /* start with the object after this one */ + do { + otmp = !by_nexthere ? otmp->nobj : otmp->nexthere; + if (!otmp) break; + } while (otmp->otyp != type); - return otmp; + return otmp; } struct obj * carrying(type) register int type; { - register struct obj *otmp; + register struct obj *otmp; - for(otmp = invent; otmp; otmp = otmp->nobj) - if(otmp->otyp == type) - return(otmp); - return((struct obj *) 0); + for(otmp = invent; otmp; otmp = otmp->nobj) + if(otmp->otyp == type) + return(otmp); + return((struct obj *) 0); } const char * currency(amount) long amount; { - if (amount == 1L) return "zorkmid"; - else return "zorkmids"; + if (amount == 1L) return "zorkmid"; + else return "zorkmids"; } boolean have_lizard() { - register struct obj *otmp; + register struct obj *otmp; - for(otmp = invent; otmp; otmp = otmp->nobj) - if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD) - return(TRUE); - return(FALSE); + for(otmp = invent; otmp; otmp = otmp->nobj) + if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD) + return(TRUE); + return(FALSE); } struct obj * @@ -629,15 +641,15 @@ o_on(id, objchn) unsigned int id; register struct obj *objchn; { - struct obj *temp; + struct obj *temp; - while(objchn) { - if(objchn->o_id == id) return(objchn); - if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj))) - return temp; - objchn = objchn->nobj; - } - return((struct obj *) 0); + while(objchn) { + if(objchn->o_id == id) return(objchn); + if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj))) + return temp; + objchn = objchn->nobj; + } + return((struct obj *) 0); } boolean @@ -645,23 +657,23 @@ obj_here(obj, x, y) register struct obj *obj; int x, y; { - register struct obj *otmp; + register struct obj *otmp; - for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) - if(obj == otmp) return(TRUE); - return(FALSE); + for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) + if(obj == otmp) return(TRUE); + return(FALSE); } struct obj * g_at(x,y) register int x, y; { - register struct obj *obj = level.objects[x][y]; - while(obj) { - if (obj->oclass == COIN_CLASS) return obj; - obj = obj->nexthere; - } - return((struct obj *)0); + register struct obj *obj = level.objects[x][y]; + while(obj) { + if (obj->oclass == COIN_CLASS) return obj; + obj = obj->nexthere; + } + return((struct obj *)0); } STATIC_OVL void @@ -669,38 +681,38 @@ compactify(buf) register char *buf; /* compact a string of inventory letters by dashing runs of letters */ { - register int i1 = 1, i2 = 1; - register char ilet, ilet1, ilet2; - - ilet2 = buf[0]; - ilet1 = buf[1]; - buf[++i2] = buf[++i1]; - ilet = buf[i1]; - while(ilet) { - if(ilet == ilet1+1) { - if(ilet1 == ilet2+1) - buf[i2 - 1] = ilet1 = '-'; - else if(ilet2 == '-') { - buf[i2 - 1] = ++ilet1; - buf[i2] = buf[++i1]; - ilet = buf[i1]; - continue; - } - } else if (ilet == NOINVSYM) { - /* compact three or more consecutive '#' - characters into "#-#" */ - if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && - buf[i2 - 1] == NOINVSYM) - buf[i2 - 1] = '-'; - else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && - buf[i2 - 2] == '-' && buf[i2 - 1] == NOINVSYM) - --i2; - } - ilet2 = ilet1; - ilet1 = ilet; - buf[++i2] = buf[++i1]; - ilet = buf[i1]; - } + register int i1 = 1, i2 = 1; + register char ilet, ilet1, ilet2; + + ilet2 = buf[0]; + ilet1 = buf[1]; + buf[++i2] = buf[++i1]; + ilet = buf[i1]; + while(ilet) { + if(ilet == ilet1+1) { + if(ilet1 == ilet2+1) + buf[i2 - 1] = ilet1 = '-'; + else if(ilet2 == '-') { + buf[i2 - 1] = ++ilet1; + buf[i2] = buf[++i1]; + ilet = buf[i1]; + continue; + } + } else if (ilet == NOINVSYM) { + /* compact three or more consecutive '#' + characters into "#-#" */ + if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && + buf[i2 - 1] == NOINVSYM) + buf[i2 - 1] = '-'; + else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && + buf[i2 - 2] == '-' && buf[i2 - 1] == NOINVSYM) + --i2; + } + ilet2 = ilet1; + ilet1 = ilet; + buf[++i2] = buf[++i1]; + ilet = buf[i1]; + } } /* some objects shouldn't be split when count given to getobj or askchain */ @@ -709,7 +721,7 @@ splittable(obj) struct obj *obj; { return !((obj->otyp == LOADSTONE && obj->cursed) || - (obj == uwep && welded(uwep))); + (obj == uwep && welded(uwep))); } /* match the prompt for either 'T' or 'R' command */ @@ -740,313 +752,313 @@ struct obj * getobj(let,word) register const char *let,*word; { - register struct obj *otmp; - register char ilet; - char buf[BUFSZ], qbuf[QBUFSZ]; - char lets[BUFSZ], altlets[BUFSZ], *ap; - register int foo = 0; - register char *bp = buf; - xchar allowcnt = 0; /* 0, 1 or 2 */ - struct obj *firstobj = invent; - boolean usegold = FALSE; /* can't use gold because its illegal */ - boolean allowall = FALSE; - boolean allownone = FALSE; - boolean useboulder = FALSE; - xchar foox = 0; - long cnt, prevcnt; - boolean prezero; - long dummymask; - - if(*let == ALLOW_COUNT) let++, allowcnt = 1; - if(*let == COIN_CLASS) let++, usegold = TRUE; - - /* Equivalent of an "ugly check" for gold */ - if (usegold && !strcmp(word, "eat") && - (!metallivorous(youmonst.data) - || youmonst.data == &mons[PM_RUST_MONSTER])) - usegold = FALSE; - - if(*let == ALL_CLASSES) let++, allowall = TRUE; - if(*let == ALLOW_NONE) let++, allownone = TRUE; - /* "ugly check" for reading fortune cookies, part 1 */ - /* The normal 'ugly check' keeps the object on the inventory list. - * We don't want to do that for shirts/cookies, so the check for - * them is handled a bit differently (and also requires that we set - * allowall in the caller) - */ - if(allowall && !strcmp(word, "read")) allowall = FALSE; - - /* another ugly check: show boulders (not statues) */ - if(*let == WEAPON_CLASS && - !strcmp(word, "throw") && throws_rocks(youmonst.data)) - useboulder = TRUE; - - if(allownone) *bp++ = '-'; - if(bp > buf && bp[-1] == '-') *bp++ = ' '; - ap = altlets; - - if (!flags.invlet_constant) reassign(); - - for (otmp = firstobj; otmp; otmp = otmp->nobj) { - if (&bp[foo] == &buf[sizeof buf - 1] || - ap == &altlets[sizeof altlets - 1]) { - /* we must have a huge number of NOINVSYM items somehow */ - impossible("getobj: inventory overflow"); - break; - } - - if (!*let || index(let, otmp->oclass) - || (usegold && otmp->invlet == GOLD_SYM) - || (useboulder && otmp->otyp == BOULDER) - ) { - register int otyp = otmp->otyp; - bp[foo++] = otmp->invlet; - - /* ugly check: remove inappropriate things */ - if ((taking_off(word) && - !(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) - || (putting_on(word) && - (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) - /* already worn */ + register struct obj *otmp; + register char ilet; + char buf[BUFSZ], qbuf[QBUFSZ]; + char lets[BUFSZ], altlets[BUFSZ], *ap; + register int foo = 0; + register char *bp = buf; + xchar allowcnt = 0; /* 0, 1 or 2 */ + struct obj *firstobj = invent; + boolean usegold = FALSE; /* can't use gold because its illegal */ + boolean allowall = FALSE; + boolean allownone = FALSE; + boolean useboulder = FALSE; + xchar foox = 0; + long cnt, prevcnt; + boolean prezero; + long dummymask; + + if(*let == ALLOW_COUNT) let++, allowcnt = 1; + if(*let == COIN_CLASS) let++, usegold = TRUE; + + /* Equivalent of an "ugly check" for gold */ + if (usegold && !strcmp(word, "eat") && + (!metallivorous(youmonst.data) + || youmonst.data == &mons[PM_RUST_MONSTER])) + usegold = FALSE; + + if(*let == ALL_CLASSES) let++, allowall = TRUE; + if(*let == ALLOW_NONE) let++, allownone = TRUE; + /* "ugly check" for reading fortune cookies, part 1 */ + /* The normal 'ugly check' keeps the object on the inventory list. + * We don't want to do that for shirts/cookies, so the check for + * them is handled a bit differently (and also requires that we set + * allowall in the caller) + */ + if(allowall && !strcmp(word, "read")) allowall = FALSE; + + /* another ugly check: show boulders (not statues) */ + if(*let == WEAPON_CLASS && + !strcmp(word, "throw") && throws_rocks(youmonst.data)) + useboulder = TRUE; + + if(allownone) *bp++ = '-'; + if(bp > buf && bp[-1] == '-') *bp++ = ' '; + ap = altlets; + + if (!flags.invlet_constant) reassign(); + + for (otmp = firstobj; otmp; otmp = otmp->nobj) { + if (&bp[foo] == &buf[sizeof buf - 1] || + ap == &altlets[sizeof altlets - 1]) { + /* we must have a huge number of NOINVSYM items somehow */ + impossible("getobj: inventory overflow"); + break; + } + + if (!*let || index(let, otmp->oclass) + || (usegold && otmp->invlet == GOLD_SYM) + || (useboulder && otmp->otyp == BOULDER) + ) { + register int otyp = otmp->otyp; + bp[foo++] = otmp->invlet; + + /* ugly check: remove inappropriate things */ + if ((taking_off(word) && + !(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) + || (putting_on(word) && + (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) + /* already worn */ #if 0 /* 3.4.1 -- include currently wielded weapon among the choices */ - || (!strcmp(word, "wield") && - (otmp->owornmask & W_WEP)) + || (!strcmp(word, "wield") && + (otmp->owornmask & W_WEP)) #endif - || (!strcmp(word, "ready") && - (otmp == uwep || (otmp == uswapwep && u.twoweap))) - || ((!strcmp(word, "dip") || !strcmp(word, "grease")) && - inaccessible_equipment(otmp, (const char *)0 , FALSE)) - ) { - foo--; - foox++; - } - - /* Second ugly check; unlike the first it won't trigger an - * "else" in "you don't have anything else to ___". - */ - else if ((putting_on(word) && - ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) || - (otmp->oclass == TOOL_CLASS && - otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES))) - || (!strcmp(word, "wield") && - (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) - || (!strcmp(word, "eat") && !is_edible(otmp)) - || (!strcmp(word, "sacrifice") && - (otyp != CORPSE && - otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR)) - || (!strcmp(word, "write with") && - (otmp->oclass == TOOL_CLASS && - otyp != MAGIC_MARKER && otyp != TOWEL)) - || (!strcmp(word, "tin") && - (otyp != CORPSE || !tinnable(otmp))) - || (!strcmp(word, "rub") && - ((otmp->oclass == TOOL_CLASS && - otyp != OIL_LAMP && otyp != MAGIC_LAMP && - otyp != BRASS_LANTERN) || - (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) - || ((!strcmp(word, "use or apply") || - !strcmp(word, "untrap with")) && - /* Picks, axes, pole-weapons, bullwhips */ - ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) && - !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) || - (otmp->oclass == POTION_CLASS && - /* only applicable potion is oil, and it will only - be offered as a choice when already discovered */ - (otyp != POT_OIL || !otmp->dknown || - !objects[POT_OIL].oc_name_known)) || - (otmp->oclass == FOOD_CLASS && - otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) || - (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) - || (!strcmp(word, "invoke") && - (!otmp->oartifact && !objects[otyp].oc_unique && - (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) && - otyp != CRYSTAL_BALL && /* #invoke synonym for apply */ - /* note: presenting the possibility of invoking non-artifact - mirrors and/or lamps is a simply a cruel deception... */ - otyp != MIRROR && otyp != MAGIC_LAMP && - (otyp != OIL_LAMP || /* don't list known oil lamp */ - (otmp->dknown && objects[OIL_LAMP].oc_name_known)))) - || (!strcmp(word, "untrap with") && - (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)) - || (!strcmp(word, "tip") && !Is_container(otmp) && - /* include horn of plenty if sufficiently discovered */ - (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown || - !objects[HORN_OF_PLENTY].oc_name_known)) - || (!strcmp(word, "charge") && !is_chargeable(otmp)) - || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) - ) - foo--; - /* ugly check for unworn armor that can't be worn */ - else if ((putting_on(word) && *let == ARMOR_CLASS && - !canwearobj(otmp, &dummymask, FALSE)) - /* or unsuitable items rubbed on known touchstone */ - || (!strncmp(word, "rub on the stone", 16) && - *let == GEM_CLASS && - otmp->dknown && objects[otyp].oc_name_known) - /* suppress corpses on astral, amulets elsewhere */ - || (!strcmp(word, "sacrifice") && - /* (!astral && amulet) || (astral && !amulet) */ - (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) - /* suppress container being stashed into */ - || (!strcmp(word, "stash") && !ck_bag(otmp)) - /* worn armor or accessory covered by cursed worn armor */ - || (taking_off(word) && - inaccessible_equipment(otmp, (const char *)0, TRUE)) - ) { - /* acceptable but not listed as likely candidate */ - foo--; - allowall = TRUE; - *ap++ = otmp->invlet; - } - } else { - - /* "ugly check" for reading fortune cookies, part 2 */ - if ((!strcmp(word, "read") + || (!strcmp(word, "ready") && + (otmp == uwep || (otmp == uswapwep && u.twoweap))) + || ((!strcmp(word, "dip") || !strcmp(word, "grease")) && + inaccessible_equipment(otmp, (const char *)0 , FALSE)) + ) { + foo--; + foox++; + } + + /* Second ugly check; unlike the first it won't trigger an + * "else" in "you don't have anything else to ___". + */ + else if ((putting_on(word) && + ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) || + (otmp->oclass == TOOL_CLASS && + otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES))) + || (!strcmp(word, "wield") && + (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) + || (!strcmp(word, "eat") && !is_edible(otmp)) + || (!strcmp(word, "sacrifice") && + (otyp != CORPSE && + otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR)) + || (!strcmp(word, "write with") && + (otmp->oclass == TOOL_CLASS && + otyp != MAGIC_MARKER && otyp != TOWEL)) + || (!strcmp(word, "tin") && + (otyp != CORPSE || !tinnable(otmp))) + || (!strcmp(word, "rub") && + ((otmp->oclass == TOOL_CLASS && + otyp != OIL_LAMP && otyp != MAGIC_LAMP && + otyp != BRASS_LANTERN) || + (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) + || ((!strcmp(word, "use or apply") || + !strcmp(word, "untrap with")) && + /* Picks, axes, pole-weapons, bullwhips */ + ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) && + !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) || + (otmp->oclass == POTION_CLASS && + /* only applicable potion is oil, and it will only + be offered as a choice when already discovered */ + (otyp != POT_OIL || !otmp->dknown || + !objects[POT_OIL].oc_name_known)) || + (otmp->oclass == FOOD_CLASS && + otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) || + (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) + || (!strcmp(word, "invoke") && + (!otmp->oartifact && !objects[otyp].oc_unique && + (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) && + otyp != CRYSTAL_BALL && /* #invoke synonym for apply */ + /* note: presenting the possibility of invoking non-artifact + mirrors and/or lamps is a simply a cruel deception... */ + otyp != MIRROR && otyp != MAGIC_LAMP && + (otyp != OIL_LAMP || /* don't list known oil lamp */ + (otmp->dknown && objects[OIL_LAMP].oc_name_known)))) + || (!strcmp(word, "untrap with") && + (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)) + || (!strcmp(word, "tip") && !Is_container(otmp) && + /* include horn of plenty if sufficiently discovered */ + (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown || + !objects[HORN_OF_PLENTY].oc_name_known)) + || (!strcmp(word, "charge") && !is_chargeable(otmp)) + || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) + ) + foo--; + /* ugly check for unworn armor that can't be worn */ + else if ((putting_on(word) && *let == ARMOR_CLASS && + !canwearobj(otmp, &dummymask, FALSE)) + /* or unsuitable items rubbed on known touchstone */ + || (!strncmp(word, "rub on the stone", 16) && + *let == GEM_CLASS && + otmp->dknown && objects[otyp].oc_name_known) + /* suppress corpses on astral, amulets elsewhere */ + || (!strcmp(word, "sacrifice") && + /* (!astral && amulet) || (astral && !amulet) */ + (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) + /* suppress container being stashed into */ + || (!strcmp(word, "stash") && !ck_bag(otmp)) + /* worn armor or accessory covered by cursed worn armor */ + || (taking_off(word) && + inaccessible_equipment(otmp, (const char *)0, TRUE)) + ) { + /* acceptable but not listed as likely candidate */ + foo--; + allowall = TRUE; + *ap++ = otmp->invlet; + } + } else { + + /* "ugly check" for reading fortune cookies, part 2 */ + if ((!strcmp(word, "read") && (otmp->otyp == FORTUNE_COOKIE || otmp->otyp == T_SHIRT))) - allowall = TRUE; - } - } - bp[foo] = 0; - if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0; - Strcpy(lets, bp); /* necessary since we destroy buf */ - if(foo > 5) /* compactify string */ - compactify(bp); - *ap = '\0'; - - if(!foo && !allowall && !allownone) { - You("don't have anything %sto %s.", - foox ? "else " : "", word); - return((struct obj *)0); - } - for(;;) { - cnt = 0; - if (allowcnt == 2) allowcnt = 1; /* abort previous count */ - prezero = FALSE; - if(!buf[0]) { - Sprintf(qbuf, "What do you want to %s? [*]", word); - } else { - Sprintf(qbuf, "What do you want to %s? [%s or ?*]", - word, buf); - } - if (in_doagain) - ilet = readchar(); - else - ilet = yn_function(qbuf, (char *)0, '\0'); - if (digit(ilet) && !allowcnt) { - pline("No count allowed with this command."); - continue; - } - if (ilet == '0') prezero = TRUE; - while (digit(ilet)) { - if (ilet != '?' && ilet != '*') savech(ilet); - /* accumulate unless cnt has overflowed */ - if (allowcnt < 3) { - prevcnt = cnt; - cnt = 10L * cnt + (long)(ilet - '0'); - /* signal presence of cnt */ - allowcnt = (cnt >= prevcnt) ? 2 : 3; - } - ilet = readchar(); - } - if (allowcnt == 3) { - /* overflow detected; force cnt to be invalid */ - cnt = -1L; - allowcnt = 2; - } - if(index(quitchars,ilet)) { - if(flags.verbose) - pline1(Never_mind); - return((struct obj *)0); - } - if(ilet == '-') { - return(allownone ? &zeroobj : (struct obj *) 0); - } - if(ilet == def_oc_syms[COIN_CLASS].sym) { - if (!usegold) { - You("cannot %s gold.", word); - return(struct obj *)0; - } - /* Historic note: early Nethack had a bug which was - * first reported for Larn, where trying to drop 2^32-n - * gold pieces was allowed, and did interesting things - * to your money supply. The LRS is the tax bureau - * from Larn. - */ - if (allowcnt == 2 && cnt <= 0) { - if (cnt < 0 || !prezero) - pline_The( - "LRS would be very interested to know you have that much."); - return (struct obj *)0; - } - - } - if(ilet == '?' || ilet == '*') { - char *allowed_choices = (ilet == '?') ? lets : (char *)0; - long ctmp = 0; - - if (ilet == '?' && !*lets && *altlets) - allowed_choices = altlets; - ilet = display_pickinv(allowed_choices, TRUE, - allowcnt ? &ctmp : (long *)0); - if(!ilet) continue; - if (allowcnt && ctmp >= 0) { - cnt = ctmp; - if (!cnt) prezero = TRUE; - allowcnt = 2; - } - if(ilet == '\033') { - if(flags.verbose) - pline1(Never_mind); - return((struct obj *)0); - } - /* they typed a letter (not a space) at the prompt */ - } - if(allowcnt == 2 && !strcmp(word,"throw")) { - /* permit counts for throwing gold, but don't accept - * counts for other things since the throw code will - * split off a single item anyway */ - if (ilet != def_oc_syms[COIN_CLASS].sym) - allowcnt = 1; - if(cnt == 0 && prezero) return((struct obj *)0); - if(cnt > 1) { - You("can only throw one item at a time."); - continue; - } - } - context.botl = 1; /* May have changed the amount of money */ - savech(ilet); - for (otmp = invent; otmp; otmp = otmp->nobj) - if (otmp->invlet == ilet) break; - if(!otmp) { - You("don't have that object."); - if (in_doagain) return((struct obj *) 0); - continue; - } else if (cnt < 0 || otmp->quan < cnt) { - You("don't have that many! You have only %ld.", - otmp->quan); - if (in_doagain) return((struct obj *) 0); - continue; - } - break; - } - if(!allowall && let && !index(let,otmp->oclass) - && !(usegold && otmp->oclass == COIN_CLASS) - ) { - silly_thing(word, otmp); - return((struct obj *)0); - } - if(allowcnt == 2) { /* cnt given */ - if(cnt == 0) return (struct obj *)0; - if(cnt != otmp->quan) { - /* don't split a stack of cursed loadstones */ - if (splittable(otmp)) - otmp = splitobj(otmp, cnt); - else if (otmp->otyp == LOADSTONE && otmp->cursed) - /* kludge for canletgo()'s can't-drop-this message */ - otmp->corpsenm = (int) cnt; - } - } - return(otmp); + allowall = TRUE; + } + } + bp[foo] = 0; + if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0; + Strcpy(lets, bp); /* necessary since we destroy buf */ + if(foo > 5) /* compactify string */ + compactify(bp); + *ap = '\0'; + + if(!foo && !allowall && !allownone) { + You("don't have anything %sto %s.", + foox ? "else " : "", word); + return((struct obj *)0); + } + for(;;) { + cnt = 0; + if (allowcnt == 2) allowcnt = 1; /* abort previous count */ + prezero = FALSE; + if(!buf[0]) { + Sprintf(qbuf, "What do you want to %s? [*]", word); + } else { + Sprintf(qbuf, "What do you want to %s? [%s or ?*]", + word, buf); + } + if (in_doagain) + ilet = readchar(); + else + ilet = yn_function(qbuf, (char *)0, '\0'); + if (digit(ilet) && !allowcnt) { + pline("No count allowed with this command."); + continue; + } + if (ilet == '0') prezero = TRUE; + while (digit(ilet)) { + if (ilet != '?' && ilet != '*') savech(ilet); + /* accumulate unless cnt has overflowed */ + if (allowcnt < 3) { + prevcnt = cnt; + cnt = 10L * cnt + (long)(ilet - '0'); + /* signal presence of cnt */ + allowcnt = (cnt >= prevcnt) ? 2 : 3; + } + ilet = readchar(); + } + if (allowcnt == 3) { + /* overflow detected; force cnt to be invalid */ + cnt = -1L; + allowcnt = 2; + } + if(index(quitchars,ilet)) { + if(flags.verbose) + pline1(Never_mind); + return((struct obj *)0); + } + if(ilet == '-') { + return(allownone ? &zeroobj : (struct obj *) 0); + } + if(ilet == def_oc_syms[COIN_CLASS].sym) { + if (!usegold) { + You("cannot %s gold.", word); + return(struct obj *)0; + } + /* Historic note: early Nethack had a bug which was + * first reported for Larn, where trying to drop 2^32-n + * gold pieces was allowed, and did interesting things + * to your money supply. The LRS is the tax bureau + * from Larn. + */ + if (allowcnt == 2 && cnt <= 0) { + if (cnt < 0 || !prezero) + pline_The( + "LRS would be very interested to know you have that much."); + return (struct obj *)0; + } + + } + if(ilet == '?' || ilet == '*') { + char *allowed_choices = (ilet == '?') ? lets : (char *)0; + long ctmp = 0; + + if (ilet == '?' && !*lets && *altlets) + allowed_choices = altlets; + ilet = display_pickinv(allowed_choices, TRUE, + allowcnt ? &ctmp : (long *)0); + if(!ilet) continue; + if (allowcnt && ctmp >= 0) { + cnt = ctmp; + if (!cnt) prezero = TRUE; + allowcnt = 2; + } + if(ilet == '\033') { + if(flags.verbose) + pline1(Never_mind); + return((struct obj *)0); + } + /* they typed a letter (not a space) at the prompt */ + } + if(allowcnt == 2 && !strcmp(word,"throw")) { + /* permit counts for throwing gold, but don't accept + * counts for other things since the throw code will + * split off a single item anyway */ + if (ilet != def_oc_syms[COIN_CLASS].sym) + allowcnt = 1; + if(cnt == 0 && prezero) return((struct obj *)0); + if(cnt > 1) { + You("can only throw one item at a time."); + continue; + } + } + context.botl = 1; /* May have changed the amount of money */ + savech(ilet); + for (otmp = invent; otmp; otmp = otmp->nobj) + if (otmp->invlet == ilet) break; + if(!otmp) { + You("don't have that object."); + if (in_doagain) return((struct obj *) 0); + continue; + } else if (cnt < 0 || otmp->quan < cnt) { + You("don't have that many! You have only %ld.", + otmp->quan); + if (in_doagain) return((struct obj *) 0); + continue; + } + break; + } + if(!allowall && let && !index(let,otmp->oclass) + && !(usegold && otmp->oclass == COIN_CLASS) + ) { + silly_thing(word, otmp); + return((struct obj *)0); + } + if(allowcnt == 2) { /* cnt given */ + if(cnt == 0) return (struct obj *)0; + if(cnt != otmp->quan) { + /* don't split a stack of cursed loadstones */ + if (splittable(otmp)) + otmp = splitobj(otmp, cnt); + else if (otmp->otyp == LOADSTONE && otmp->cursed) + /* kludge for canletgo()'s can't-drop-this message */ + otmp->corpsenm = (int) cnt; + } + } + return(otmp); } void @@ -1054,57 +1066,57 @@ silly_thing(word, otmp) const char *word; struct obj *otmp; { - const char *s1, *s2, *s3, *what; - int ocls = otmp->oclass, otyp = otmp->otyp; - - s1 = s2 = s3 = 0; - /* check for attempted use of accessory commands ('P','R') on armor - and for corresponding armor commands ('W','T') on accessories */ - if (ocls == ARMOR_CLASS) { - if (!strcmp(word, "put on")) - s1 = "W", s2 = "wear", s3 = ""; - else if (!strcmp(word, "remove")) - s1 = "T", s2 = "take", s3 = " off"; - } else if ((ocls == RING_CLASS || otyp == MEAT_RING) || - ocls == AMULET_CLASS || - (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) { - if (!strcmp(word, "wear")) - s1 = "P", s2 = "put", s3 = " on"; - else if (!strcmp(word, "take off")) - s1 = "R", s2 = "remove", s3 = ""; - } - if (s1) { - what = "that"; - /* quantity for armor and accessory objects is always 1, - but some things should be referred to as plural */ - if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp)) - what = "those"; - pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); - } else { - pline(silly_thing_to, word); - } + const char *s1, *s2, *s3, *what; + int ocls = otmp->oclass, otyp = otmp->otyp; + + s1 = s2 = s3 = 0; + /* check for attempted use of accessory commands ('P','R') on armor + and for corresponding armor commands ('W','T') on accessories */ + if (ocls == ARMOR_CLASS) { + if (!strcmp(word, "put on")) + s1 = "W", s2 = "wear", s3 = ""; + else if (!strcmp(word, "remove")) + s1 = "T", s2 = "take", s3 = " off"; + } else if ((ocls == RING_CLASS || otyp == MEAT_RING) || + ocls == AMULET_CLASS || + (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) { + if (!strcmp(word, "wear")) + s1 = "P", s2 = "put", s3 = " on"; + else if (!strcmp(word, "take off")) + s1 = "R", s2 = "remove", s3 = ""; + } + if (s1) { + what = "that"; + /* quantity for armor and accessory objects is always 1, + but some things should be referred to as plural */ + if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp)) + what = "those"; + pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); + } else { + pline(silly_thing_to, word); + } } STATIC_PTR int ckvalidcat(otmp) register struct obj *otmp; { - /* use allow_category() from pickup.c */ - return((int)allow_category(otmp)); + /* use allow_category() from pickup.c */ + return((int)allow_category(otmp)); } STATIC_PTR int ckunpaid(otmp) register struct obj *otmp; { - return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp))); + return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp))); } boolean wearing_armor() { - return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms - || uarmu)); + return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms + || uarmu)); } boolean @@ -1112,7 +1124,7 @@ is_worn(otmp) register struct obj *otmp; { return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | - W_SADDLE | W_WEP | W_SWAPWEP | W_QUIVER)))); + W_SADDLE | W_WEP | W_SWAPWEP | W_QUIVER)))); } /* extra xprname() input that askchain() can't pass through safe_qbuf() */ @@ -1127,8 +1139,8 @@ safeq_xprname(obj) struct obj *obj; { return xprname(obj, (char *)0, - safeq_xprn_ctx.let, safeq_xprn_ctx.dot, - 0L, 0L); + safeq_xprn_ctx.let, safeq_xprn_ctx.dot, + 0L, 0L); } /* alternate safe_qbuf() -> short_oname() callback */ @@ -1137,12 +1149,12 @@ safeq_shortxprname(obj) struct obj *obj; { return xprname(obj, ansimpleoname(obj), - safeq_xprn_ctx.let, safeq_xprn_ctx.dot, - 0L, 0L); + safeq_xprn_ctx.let, safeq_xprn_ctx.dot, + 0L, 0L); } static NEARDATA const char removeables[] = - { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 }; + { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 }; /* interactive version of getobj - used for Drop, Identify and */ /* Takeoff (A). Return the number of times fn was called successfully */ @@ -1154,156 +1166,156 @@ int FDECL((*fn),(OBJ_P)), mx; boolean combo; /* combination menu flag */ unsigned *resultflags; { - int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0; - boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0; - boolean takeoff, ident, allflag, m_seen; - int itemcount; - int oletct, iletct, unpaid, oc_of_sym; - char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5]; - char extra_removeables[3+1]; /* uwep,uswapwep,uquiver */ - char buf[BUFSZ], qbuf[QBUFSZ]; - - if (resultflags) *resultflags = 0; - takeoff = ident = allflag = m_seen = FALSE; - if(!invent){ - You("have nothing to %s.", word); - return(0); - } - add_valid_menu_class(0); /* reset */ - if (taking_off(word)) { - takeoff = TRUE; - filter = is_worn; - } else if (!strcmp(word, "identify")) { - ident = TRUE; - filter = not_fully_identified; - } - - iletct = collect_obj_classes(ilets, invent, - FALSE, - filter, &itemcount); - unpaid = count_unpaid(invent); - - if (ident && !iletct) { - return -1; /* no further identifications */ - } else if (!takeoff && (unpaid || invent)) { - ilets[iletct++] = ' '; - if (unpaid) ilets[iletct++] = 'u'; - if (count_buc(invent, BUC_BLESSED)) ilets[iletct++] = 'B'; - if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U'; - if (count_buc(invent, BUC_CURSED)) ilets[iletct++] = 'C'; - if (count_buc(invent, BUC_UNKNOWN)) ilets[iletct++] = 'X'; - if (invent) ilets[iletct++] = 'a'; - } else if (takeoff && invent) { - ilets[iletct++] = ' '; - } - ilets[iletct++] = 'i'; - if (!combo) - ilets[iletct++] = 'm'; /* allow menu presentation on request */ - ilets[iletct] = '\0'; - - for (;;) { - Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]", - word, ilets); - getlin(qbuf, buf); - if (buf[0] == '\033') return(0); - if (index(buf, 'i')) { - if (display_inventory((char *)0, TRUE) == '\033') return 0; - } else - break; - } - - extra_removeables[0] = '\0'; - if (takeoff) { - /* arbitrary types of items can be placed in the weapon slots - [any duplicate entries in extra_removeables[] won't matter] */ - if (uwep) (void)strkitten(extra_removeables, uwep->oclass); - if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass); - if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass); - } - - ip = buf; - olets[oletct = 0] = '\0'; - while ((sym = *ip++) != '\0') { - if (sym == ' ') continue; - oc_of_sym = def_char_to_objclass(sym); - if (takeoff && oc_of_sym != MAXOCLASSES) { - if (index(extra_removeables, oc_of_sym)) { - ; /* skip rest of takeoff checks */ - } else if (!index(removeables, oc_of_sym)) { - pline("Not applicable."); - return 0; - } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) { - noarmor(FALSE); - return 0; - } else if (oc_of_sym == WEAPON_CLASS && - !uwep && !uswapwep && !uquiver) { - You("are not wielding anything."); - return 0; - } else if (oc_of_sym == RING_CLASS && !uright && !uleft) { - You("are not wearing rings."); - return 0; - } else if (oc_of_sym == AMULET_CLASS && !uamul) { - You("are not wearing an amulet."); - return 0; - } else if (oc_of_sym == TOOL_CLASS && !ublindf) { - You("are not wearing a blindfold."); - return 0; - } - } - - if (oc_of_sym == COIN_CLASS && !combo) { - context.botl = 1; - } else if (sym == 'a') { - allflag = TRUE; - } else if (sym == 'A') { - /* same as the default */ ; - } else if (sym == 'u') { - add_valid_menu_class('u'); - ckfn = ckunpaid; - } else if (sym == 'B') { - add_valid_menu_class('B'); - ckfn = ckvalidcat; - } else if (sym == 'U') { - add_valid_menu_class('U'); - ckfn = ckvalidcat; - } else if (sym == 'C') { - add_valid_menu_class('C'); - ckfn = ckvalidcat; - } else if (sym == 'X') { - add_valid_menu_class('X'); - ckfn = ckvalidcat; - } else if (sym == 'm') { - m_seen = TRUE; - } else if (oc_of_sym == MAXOCLASSES) { - You("don't have any %c's.", sym); - } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */ - if (!index(olets, oc_of_sym)) { - add_valid_menu_class(oc_of_sym); - olets[oletct++] = oc_of_sym; - olets[oletct] = 0; - } - } - } - - if (m_seen) - return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3; - else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) - return 0; - else /*!!!! if (allowgold == 2 && !oletct) - !!!! return 1; you dropped gold (or at least tried to) + int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0; + boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0; + boolean takeoff, ident, allflag, m_seen; + int itemcount; + int oletct, iletct, unpaid, oc_of_sym; + char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5]; + char extra_removeables[3+1]; /* uwep,uswapwep,uquiver */ + char buf[BUFSZ], qbuf[QBUFSZ]; + + if (resultflags) *resultflags = 0; + takeoff = ident = allflag = m_seen = FALSE; + if(!invent){ + You("have nothing to %s.", word); + return(0); + } + add_valid_menu_class(0); /* reset */ + if (taking_off(word)) { + takeoff = TRUE; + filter = is_worn; + } else if (!strcmp(word, "identify")) { + ident = TRUE; + filter = not_fully_identified; + } + + iletct = collect_obj_classes(ilets, invent, + FALSE, + filter, &itemcount); + unpaid = count_unpaid(invent); + + if (ident && !iletct) { + return -1; /* no further identifications */ + } else if (!takeoff && (unpaid || invent)) { + ilets[iletct++] = ' '; + if (unpaid) ilets[iletct++] = 'u'; + if (count_buc(invent, BUC_BLESSED)) ilets[iletct++] = 'B'; + if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U'; + if (count_buc(invent, BUC_CURSED)) ilets[iletct++] = 'C'; + if (count_buc(invent, BUC_UNKNOWN)) ilets[iletct++] = 'X'; + if (invent) ilets[iletct++] = 'a'; + } else if (takeoff && invent) { + ilets[iletct++] = ' '; + } + ilets[iletct++] = 'i'; + if (!combo) + ilets[iletct++] = 'm'; /* allow menu presentation on request */ + ilets[iletct] = '\0'; + + for (;;) { + Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]", + word, ilets); + getlin(qbuf, buf); + if (buf[0] == '\033') return(0); + if (index(buf, 'i')) { + if (display_inventory((char *)0, TRUE) == '\033') return 0; + } else + break; + } + + extra_removeables[0] = '\0'; + if (takeoff) { + /* arbitrary types of items can be placed in the weapon slots + [any duplicate entries in extra_removeables[] won't matter] */ + if (uwep) (void)strkitten(extra_removeables, uwep->oclass); + if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass); + if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass); + } + + ip = buf; + olets[oletct = 0] = '\0'; + while ((sym = *ip++) != '\0') { + if (sym == ' ') continue; + oc_of_sym = def_char_to_objclass(sym); + if (takeoff && oc_of_sym != MAXOCLASSES) { + if (index(extra_removeables, oc_of_sym)) { + ; /* skip rest of takeoff checks */ + } else if (!index(removeables, oc_of_sym)) { + pline("Not applicable."); + return 0; + } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) { + noarmor(FALSE); + return 0; + } else if (oc_of_sym == WEAPON_CLASS && + !uwep && !uswapwep && !uquiver) { + You("are not wielding anything."); + return 0; + } else if (oc_of_sym == RING_CLASS && !uright && !uleft) { + You("are not wearing rings."); + return 0; + } else if (oc_of_sym == AMULET_CLASS && !uamul) { + You("are not wearing an amulet."); + return 0; + } else if (oc_of_sym == TOOL_CLASS && !ublindf) { + You("are not wearing a blindfold."); + return 0; + } + } + + if (oc_of_sym == COIN_CLASS && !combo) { + context.botl = 1; + } else if (sym == 'a') { + allflag = TRUE; + } else if (sym == 'A') { + /* same as the default */ ; + } else if (sym == 'u') { + add_valid_menu_class('u'); + ckfn = ckunpaid; + } else if (sym == 'B') { + add_valid_menu_class('B'); + ckfn = ckvalidcat; + } else if (sym == 'U') { + add_valid_menu_class('U'); + ckfn = ckvalidcat; + } else if (sym == 'C') { + add_valid_menu_class('C'); + ckfn = ckvalidcat; + } else if (sym == 'X') { + add_valid_menu_class('X'); + ckfn = ckvalidcat; + } else if (sym == 'm') { + m_seen = TRUE; + } else if (oc_of_sym == MAXOCLASSES) { + You("don't have any %c's.", sym); + } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */ + if (!index(olets, oc_of_sym)) { + add_valid_menu_class(oc_of_sym); + olets[oletct++] = oc_of_sym; + olets[oletct] = 0; + } + } + } + + if (m_seen) + return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3; + else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) + return 0; + else /*!!!! if (allowgold == 2 && !oletct) + !!!! return 1; you dropped gold (or at least tried to) !!!! test gold dropping - else*/ { - int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); - /* - * askchain() has already finished the job in this case - * so set a special flag to convey that back to the caller - * so that it won't continue processing. - * Fix for bug C331-1 reported by Irina Rempt-Drijfhout. - */ - if (combo && allflag && resultflags) - *resultflags |= ALL_FINISHED; - return cnt; - } + else*/ { + int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); + /* + * askchain() has already finished the job in this case + * so set a special flag to convey that back to the caller + * so that it won't continue processing. + * Fix for bug C331-1 reported by Irina Rempt-Drijfhout. + */ + if (combo && allflag && resultflags) + *resultflags |= ALL_FINISHED; + return cnt; + } } /* @@ -1320,119 +1332,119 @@ register int allflag, mx; register const char *olets, *word; /* olets is an Obj Class char array */ register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P)); { - struct obj *otmp, *otmpo; - register char sym, ilet; - register int cnt = 0, dud = 0, tmp; - boolean takeoff, nodot, ident, take_out, put_in, first, ininv; - char qbuf[QBUFSZ], qpfx[QBUFSZ]; - - takeoff = taking_off(word); - ident = !strcmp(word, "identify"); - take_out = !strcmp(word, "take out"); - put_in = !strcmp(word, "put in"); - nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || - ident || takeoff || take_out || put_in); - ininv = (*objchn == invent); - first = TRUE; - /* Changed so the askchain is interrogated in the order specified. - * For example, if a person specifies =/ then first all rings will be - * asked about followed by all wands -dgk - */ + struct obj *otmp, *otmpo; + register char sym, ilet; + register int cnt = 0, dud = 0, tmp; + boolean takeoff, nodot, ident, take_out, put_in, first, ininv; + char qbuf[QBUFSZ], qpfx[QBUFSZ]; + + takeoff = taking_off(word); + ident = !strcmp(word, "identify"); + take_out = !strcmp(word, "take out"); + put_in = !strcmp(word, "put in"); + nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || + ident || takeoff || take_out || put_in); + ininv = (*objchn == invent); + first = TRUE; + /* Changed so the askchain is interrogated in the order specified. + * For example, if a person specifies =/ then first all rings will be + * asked about followed by all wands -dgk + */ nextclass: - ilet = 'a'-1; - if (*objchn && (*objchn)->oclass == COIN_CLASS) - ilet--; /* extra iteration */ - /* - * Multiple Drop can change the invent chain while it operates - * (dropping a burning potion of oil while levitating creates - * an explosion which can destroy inventory items), so simple - * list traversal - * for (otmp = *objchn; otmp; otmp = otmp2) { - * otmp2 = otmp->nobj; - * ... - * } - * is inadeqate here. Use each object's bypass bit to keep - * track of which list elements have already been processed. - */ - bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */ - while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) { - if (ilet == 'z') ilet = 'A'; else ilet++; - if (olets && *olets && otmp->oclass != *olets) continue; - if (takeoff && !is_worn(otmp)) continue; - if (ident && !not_fully_identified(otmp)) continue; - if (ckfn && !(*ckfn)(otmp)) continue; - if (!allflag) { - safeq_xprn_ctx.let = ilet; - safeq_xprn_ctx.dot = !nodot; - *qpfx = '\0'; - if (first) { - /* traditional_loot() skips prompting when only one - class of objects is involved, so prefix the first - object being queried here with an explanation why */ - if (take_out || put_in) - Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx); - first = FALSE; - } - (void)safe_qbuf(qbuf, qpfx, "?", - otmp, ininv ? safeq_xprname : doname, - ininv ? safeq_shortxprname : ansimpleoname, - "item"); - sym = (takeoff || ident || otmp->quan < 2L) ? - nyaq(qbuf) : nyNaq(qbuf); - } else - sym = 'y'; - - otmpo = otmp; - if (sym == '#') { - /* Number was entered; split the object unless it corresponds - to 'none' or 'all'. 2 special cases: cursed loadstones and - welded weapons (eg, multiple daggers) will remain as merged - unit; done to avoid splitting an object that won't be - droppable (even if we're picking up rather than dropping). - */ - if (!yn_number) - sym = 'n'; - else { - sym = 'y'; - if (yn_number < otmp->quan && splittable(otmp)) - otmp = splitobj(otmp, yn_number); - } - } - switch(sym){ - case 'a': - allflag = 1; - case 'y': - tmp = (*fn)(otmp); - if(tmp < 0) { - if (container_gone(fn)) { - /* otmp caused magic bag to explode; - both are now gone */ - otmp = 0; /* and return */ - } else if (otmp && otmp != otmpo) { - /* split occurred, merge again */ - (void) merged(&otmpo, &otmp); - } - goto ret; - } - cnt += tmp; - if(--mx == 0) goto ret; - case 'n': - if(nodot) dud++; - default: - break; - case 'q': - /* special case for seffects() */ - if (ident) cnt = -1; - goto ret; - } - } - if (olets && *olets && *++olets) - goto nextclass; - if(!takeoff && (dud || cnt)) pline("That was all."); - else if(!dud && !cnt) pline("No applicable objects."); + ilet = 'a'-1; + if (*objchn && (*objchn)->oclass == COIN_CLASS) + ilet--; /* extra iteration */ + /* + * Multiple Drop can change the invent chain while it operates + * (dropping a burning potion of oil while levitating creates + * an explosion which can destroy inventory items), so simple + * list traversal + * for (otmp = *objchn; otmp; otmp = otmp2) { + * otmp2 = otmp->nobj; + * ... + * } + * is inadeqate here. Use each object's bypass bit to keep + * track of which list elements have already been processed. + */ + bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */ + while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) { + if (ilet == 'z') ilet = 'A'; else ilet++; + if (olets && *olets && otmp->oclass != *olets) continue; + if (takeoff && !is_worn(otmp)) continue; + if (ident && !not_fully_identified(otmp)) continue; + if (ckfn && !(*ckfn)(otmp)) continue; + if (!allflag) { + safeq_xprn_ctx.let = ilet; + safeq_xprn_ctx.dot = !nodot; + *qpfx = '\0'; + if (first) { + /* traditional_loot() skips prompting when only one + class of objects is involved, so prefix the first + object being queried here with an explanation why */ + if (take_out || put_in) + Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx); + first = FALSE; + } + (void)safe_qbuf(qbuf, qpfx, "?", + otmp, ininv ? safeq_xprname : doname, + ininv ? safeq_shortxprname : ansimpleoname, + "item"); + sym = (takeoff || ident || otmp->quan < 2L) ? + nyaq(qbuf) : nyNaq(qbuf); + } else + sym = 'y'; + + otmpo = otmp; + if (sym == '#') { + /* Number was entered; split the object unless it corresponds + to 'none' or 'all'. 2 special cases: cursed loadstones and + welded weapons (eg, multiple daggers) will remain as merged + unit; done to avoid splitting an object that won't be + droppable (even if we're picking up rather than dropping). + */ + if (!yn_number) + sym = 'n'; + else { + sym = 'y'; + if (yn_number < otmp->quan && splittable(otmp)) + otmp = splitobj(otmp, yn_number); + } + } + switch(sym){ + case 'a': + allflag = 1; + case 'y': + tmp = (*fn)(otmp); + if(tmp < 0) { + if (container_gone(fn)) { + /* otmp caused magic bag to explode; + both are now gone */ + otmp = 0; /* and return */ + } else if (otmp && otmp != otmpo) { + /* split occurred, merge again */ + (void) merged(&otmpo, &otmp); + } + goto ret; + } + cnt += tmp; + if(--mx == 0) goto ret; + case 'n': + if(nodot) dud++; + default: + break; + case 'q': + /* special case for seffects() */ + if (ident) cnt = -1; + goto ret; + } + } + if (olets && *olets && *++olets) + goto nextclass; + if(!takeoff && (dud || cnt)) pline("That was all."); + else if(!dud && !cnt) pline("No applicable objects."); ret: - bypass_objlist(*objchn, FALSE); - return(cnt); + bypass_objlist(*objchn, FALSE); + return(cnt); } @@ -1449,9 +1461,9 @@ struct obj *otmp; if (otmp->oartifact) discover_artifact((xchar)otmp->oartifact); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; if (Is_container(otmp) || otmp->otyp == STATUE) - otmp->cknown = otmp->lknown = 1; + otmp->cknown = otmp->lknown = 1; if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) - learn_egg_type(otmp->corpsenm); + learn_egg_type(otmp->corpsenm); } /* ggetobj callback routine; identify an object and give immediate feedback */ @@ -1475,30 +1487,30 @@ int id_limit; /* assumptions: id_limit > 0 and at least one unID'd item is present */ while (id_limit) { - Sprintf(buf, "What would you like to identify %s?", - first ? "first" : "next"); - n = query_objlist(buf, invent, - SIGNAL_NOMENU|SIGNAL_ESCAPE|USE_INVLET|INVORDER_SORT, - &pick_list, PICK_ANY, not_fully_identified); - - if (n > 0) { - if (n > id_limit) n = id_limit; - for (i = 0; i < n; i++, id_limit--) - (void) identify(pick_list[i].item.a_obj); - free((genericptr_t) pick_list); - mark_synch(); /* Before we loop to pop open another menu */ - first = 0; - } else if (n == -2) { /* player used ESC to quit menu */ - break; - } else if (n == -1) { /* no eligible items found */ - pline("That was all."); - break; - } else if (!--tryct) { /* stop re-prompting */ - pline1(thats_enough_tries); - break; - } else { /* try again */ - pline("Choose an item; use ESC to decline."); - } + Sprintf(buf, "What would you like to identify %s?", + first ? "first" : "next"); + n = query_objlist(buf, invent, + SIGNAL_NOMENU|SIGNAL_ESCAPE|USE_INVLET|INVORDER_SORT, + &pick_list, PICK_ANY, not_fully_identified); + + if (n > 0) { + if (n > id_limit) n = id_limit; + for (i = 0; i < n; i++, id_limit--) + (void) identify(pick_list[i].item.a_obj); + free((genericptr_t) pick_list); + mark_synch(); /* Before we loop to pop open another menu */ + first = 0; + } else if (n == -2) { /* player used ESC to quit menu */ + break; + } else if (n == -1) { /* no eligible items found */ + pline("That was all."); + break; + } else if (!--tryct) { /* stop re-prompting */ + pline1(thats_enough_tries); + break; + } else { /* try again */ + pline("Choose an item; use ESC to decline."); + } } } @@ -1514,32 +1526,32 @@ boolean learning_id; /* true if we just read unknown identify scroll */ unid_cnt = 0; the_obj = 0; /* if unid_cnt ends up 1, this will be it */ for (obj = invent; obj; obj = obj->nobj) - if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj; + if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj; if (!unid_cnt) { - You("have already identified all %sof your possessions.", - learning_id ? "the rest " : ""); + You("have already identified all %sof your possessions.", + learning_id ? "the rest " : ""); } else if (!id_limit || id_limit >= unid_cnt) { - /* identify everything */ - if (unid_cnt == 1) { - (void) identify(the_obj); - } else { + /* identify everything */ + if (unid_cnt == 1) { + (void) identify(the_obj); + } else { - /* TODO: use fully_identify_obj and cornline/menu/whatever here */ - for (obj = invent; obj; obj = obj->nobj) - if (not_fully_identified(obj)) (void) identify(obj); + /* TODO: use fully_identify_obj and cornline/menu/whatever here */ + for (obj = invent; obj; obj = obj->nobj) + if (not_fully_identified(obj)) (void) identify(obj); - } + } } else { - /* identify up to `id_limit' items */ - n = 0; - if (flags.menu_style == MENU_TRADITIONAL) - do { - n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *)0); - if (n < 0) break; /* quit or no eligible items */ - } while ((id_limit -= n) > 0); - if (n == 0 || n < -1) - menu_identify(id_limit); + /* identify up to `id_limit' items */ + n = 0; + if (flags.menu_style == MENU_TRADITIONAL) + do { + n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *)0); + if (n < 0) break; /* quit or no eligible items */ + } while ((id_limit -= n) > 0); + if (n == 0 || n < -1) + menu_identify(id_limit); } update_inventory(); } @@ -1554,13 +1566,13 @@ learn_unseen_invent() if (Blind) return; /* sanity check */ for (otmp = invent; otmp; otmp = otmp->nobj) { - if (otmp->dknown) continue; /* already seen */ - /* set dknown, perhaps bknown (for priest[ess]) */ - (void) xname(otmp); - /* - * If object->eknown gets implemented (see learnwand(zap.c)), - * handle deferred discovery here. - */ + if (otmp->dknown) continue; /* already seen */ + /* set dknown, perhaps bknown (for priest[ess]) */ + (void) xname(otmp); + /* + * If object->eknown gets implemented (see learnwand(zap.c)), + * handle deferred discovery here. + */ } update_inventory(); } @@ -1569,11 +1581,11 @@ STATIC_OVL char obj_to_let(obj) /* should of course only be called for things in invent */ register struct obj *obj; { - if (!flags.invlet_constant) { - obj->invlet = NOINVSYM; - reassign(); - } - return obj->invlet; + if (!flags.invlet_constant) { + obj->invlet = NOINVSYM; + reassign(); + } + return obj->invlet; } /* @@ -1586,10 +1598,10 @@ const char *prefix; register struct obj *obj; long quan; { - if (!prefix) prefix = ""; - pline("%s%s%s", - prefix, *prefix ? " " : "", - xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan)); + if (!prefix) prefix = ""; + pline("%s%s%s", + prefix, *prefix ? " " : "", + xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan)); } char * @@ -1610,8 +1622,8 @@ long quan; /* if non-0, print this quantity, not obj->quan */ long savequan = 0; if (quan && obj) { - savequan = obj->quan; - obj->quan = quan; + savequan = obj->quan; + obj->quan = quan; } /* @@ -1620,15 +1632,15 @@ long quan; /* if non-0, print this quantity, not obj->quan */ * > Then the object is contained and doesn't have an inventory letter. */ if (cost != 0 || let == '*') { - /* if dot is true, we're doing Iu, otherwise Ix */ - Sprintf(li, "%c - %-45s %6ld %s", - (dot && use_invlet ? obj->invlet : let), - (txt ? txt : doname(obj)), cost, currency(cost)); + /* if dot is true, we're doing Iu, otherwise Ix */ + Sprintf(li, "%c - %-45s %6ld %s", + (dot && use_invlet ? obj->invlet : let), + (txt ? txt : doname(obj)), cost, currency(cost)); } else { - /* ordinary inventory display or pickup message */ - Sprintf(li, "%c - %s%s", - (use_invlet ? obj->invlet : let), - (txt ? txt : doname(obj)), (dot ? "." : "")); + /* ordinary inventory display or pickup message */ + Sprintf(li, "%c - %s%s", + (use_invlet ? obj->invlet : let), + (txt ? txt : doname(obj)), (dot ? "." : "")); } if (savequan) obj->quan = savequan; @@ -1639,8 +1651,8 @@ long quan; /* if non-0, print this quantity, not obj->quan */ int ddoinv() { - (void) display_inventory((char *)0, FALSE); - return 0; + (void) display_inventory((char *)0, FALSE); + return 0; } /* @@ -1659,19 +1671,19 @@ find_unpaid(list, last_found) struct obj *obj; while (list) { - if (list->unpaid) { - if (*last_found) { - /* still looking for previous unpaid object */ - if (list == *last_found) - *last_found = (struct obj *) 0; - } else - return (*last_found = list); - } - if (Has_contents(list)) { - if ((obj = find_unpaid(list->cobj, last_found)) != 0) - return obj; - } - list = list->nobj; + if (list->unpaid) { + if (*last_found) { + /* still looking for previous unpaid object */ + if (list == *last_found) + *last_found = (struct obj *) 0; + } else + return (*last_found = list); + } + if (Has_contents(list)) { + if ((obj = find_unpaid(list->cobj, last_found)) != 0) + return obj; + } + list = list->nobj; } return (struct obj *) 0; } @@ -1687,109 +1699,109 @@ register const char *lets; boolean want_reply; long* out_cnt; { - struct obj *otmp; - char ilet, ret; - char *invlet = flags.inv_order; - int n, classcount; - winid win; /* windows being used */ - static winid local_win = WIN_ERR; /* window for partial menus */ - anything any; - menu_item *selected; - - /* overriden by global flag */ - if (flags.perm_invent) { - win = (lets && *lets) ? local_win : WIN_INVEN; - /* create the first time used */ - if (win == WIN_ERR) - win = local_win = create_nhwindow(NHW_MENU); - } else - win = WIN_INVEN; - - /* - Exit early if no inventory -- but keep going if we are doing - a permanent inventory update. We need to keep going so the - permanent inventory window updates itself to remove the last - item(s) dropped. One down side: the addition of the exception - for permanent inventory window updates _can_ pop the window - up when it's not displayed -- even if it's empty -- because we - don't know at this level if its up or not. This may not be - an issue if empty checks are done before hand and the call - to here is short circuited away. - */ - if (!invent && !(flags.perm_invent && !lets && !want_reply)) { - pline("Not carrying anything."); - return 0; - } - - /* oxymoron? temporarily assign permanent inventory letters */ - if (!flags.invlet_constant) reassign(); - - if (lets && strlen(lets) == 1 && !iflags.override_ID) { - /* when only one item of interest, use pline instead of menus; - we actually use a fake message-line menu in order to allow - the user to perform selection at the --More-- prompt for tty */ - ret = '\0'; - for (otmp = invent; otmp; otmp = otmp->nobj) { - if (otmp->invlet == lets[0]) { - ret = message_menu(lets[0], - want_reply ? PICK_ONE : PICK_NONE, - xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L)); - if (out_cnt) *out_cnt = -1L; /* select all */ - break; - } - } - return ret; - } - - start_menu(win); - if (wizard && iflags.override_ID) { - char prompt[BUFSZ]; - any.a_char = -1; - /* wiz_identify stuffed the wiz_identify cmd character - into iflags.override_ID */ - Sprintf(prompt, "Debug Identify (%s to permanently identify)", - visctrl(iflags.override_ID)); - add_menu(win, NO_GLYPH, &any,' ', iflags.override_ID, ATR_NONE, - prompt, MENU_UNSELECTED); - } + struct obj *otmp; + char ilet, ret; + char *invlet = flags.inv_order; + int n, classcount; + winid win; /* windows being used */ + static winid local_win = WIN_ERR; /* window for partial menus */ + anything any; + menu_item *selected; + + /* overriden by global flag */ + if (flags.perm_invent) { + win = (lets && *lets) ? local_win : WIN_INVEN; + /* create the first time used */ + if (win == WIN_ERR) + win = local_win = create_nhwindow(NHW_MENU); + } else + win = WIN_INVEN; + + /* + Exit early if no inventory -- but keep going if we are doing + a permanent inventory update. We need to keep going so the + permanent inventory window updates itself to remove the last + item(s) dropped. One down side: the addition of the exception + for permanent inventory window updates _can_ pop the window + up when it's not displayed -- even if it's empty -- because we + don't know at this level if its up or not. This may not be + an issue if empty checks are done before hand and the call + to here is short circuited away. + */ + if (!invent && !(flags.perm_invent && !lets && !want_reply)) { + pline("Not carrying anything."); + return 0; + } + + /* oxymoron? temporarily assign permanent inventory letters */ + if (!flags.invlet_constant) reassign(); + + if (lets && strlen(lets) == 1 && !iflags.override_ID) { + /* when only one item of interest, use pline instead of menus; + we actually use a fake message-line menu in order to allow + the user to perform selection at the --More-- prompt for tty */ + ret = '\0'; + for (otmp = invent; otmp; otmp = otmp->nobj) { + if (otmp->invlet == lets[0]) { + ret = message_menu(lets[0], + want_reply ? PICK_ONE : PICK_NONE, + xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L)); + if (out_cnt) *out_cnt = -1L; /* select all */ + break; + } + } + return ret; + } + + start_menu(win); + if (wizard && iflags.override_ID) { + char prompt[BUFSZ]; + any.a_char = -1; + /* wiz_identify stuffed the wiz_identify cmd character + into iflags.override_ID */ + Sprintf(prompt, "Debug Identify (%s to permanently identify)", + visctrl(iflags.override_ID)); + add_menu(win, NO_GLYPH, &any,' ', iflags.override_ID, ATR_NONE, + prompt, MENU_UNSELECTED); + } nextclass: - classcount = 0; - any = zeroany; /* set all bits to zero */ - for(otmp = invent; otmp; otmp = otmp->nobj) { - ilet = otmp->invlet; - if(!lets || !*lets || index(lets, ilet)) { - any = zeroany; /* zero */ - if (!flags.sortpack || otmp->oclass == *invlet) { - if (flags.sortpack && !classcount) { - add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, - let_to_name(*invlet, FALSE), MENU_UNSELECTED); - classcount++; - } - any.a_char = ilet; - add_menu(win, obj_to_glyph(otmp), - &any, ilet, 0, ATR_NONE, doname(otmp), - MENU_UNSELECTED); - } - } - } - if (flags.sortpack) { - if (*++invlet) goto nextclass; - if (--invlet != venom_inv) { - invlet = venom_inv; - goto nextclass; - } - } - end_menu(win, (char *) 0); - - n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); - if (n > 0) { - ret = selected[0].item.a_char; - if (out_cnt) *out_cnt = selected[0].count; - free((genericptr_t)selected); - } else - ret = !n ? '\0' : '\033'; /* cancelled */ - - return ret; + classcount = 0; + any = zeroany; /* set all bits to zero */ + for(otmp = invent; otmp; otmp = otmp->nobj) { + ilet = otmp->invlet; + if(!lets || !*lets || index(lets, ilet)) { + any = zeroany; /* zero */ + if (!flags.sortpack || otmp->oclass == *invlet) { + if (flags.sortpack && !classcount) { + add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, + let_to_name(*invlet, FALSE), MENU_UNSELECTED); + classcount++; + } + any.a_char = ilet; + add_menu(win, obj_to_glyph(otmp), + &any, ilet, 0, ATR_NONE, doname(otmp), + MENU_UNSELECTED); + } + } + } + if (flags.sortpack) { + if (*++invlet) goto nextclass; + if (--invlet != venom_inv) { + invlet = venom_inv; + goto nextclass; + } + } + end_menu(win, (char *) 0); + + n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); + if (n > 0) { + ret = selected[0].item.a_char; + if (out_cnt) *out_cnt = selected[0].count; + free((genericptr_t)selected); + } else + ret = !n ? '\0' : '\033'; /* cancelled */ + + return ret; } /* @@ -1804,7 +1816,7 @@ display_inventory(lets, want_reply) register const char *lets; boolean want_reply; { - return display_pickinv(lets, want_reply, (long *)0); + return display_pickinv(lets, want_reply, (long *)0); } /* @@ -1815,49 +1827,49 @@ STATIC_OVL char display_used_invlets(avoidlet) char avoidlet; { - struct obj *otmp; - char ilet, ret = 0; - char *invlet = flags.inv_order; - int n, classcount, invdone = 0; - winid win; - anything any; - menu_item *selected; - - if (invent) { - win = create_nhwindow(NHW_MENU); - start_menu(win); - while (!invdone) { - any = zeroany; /* set all bits to zero */ - classcount = 0; - for(otmp = invent; otmp; otmp = otmp->nobj) { - ilet = otmp->invlet; - if (ilet == avoidlet) continue; - if (!flags.sortpack || otmp->oclass == *invlet) { - if (flags.sortpack && !classcount) { - any = zeroany; /* zero */ - add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, - let_to_name(*invlet, FALSE), MENU_UNSELECTED); - classcount++; - } - any.a_char = ilet; - add_menu(win, obj_to_glyph(otmp), - &any, ilet, 0, ATR_NONE, doname(otmp), - MENU_UNSELECTED); - } - } - if (flags.sortpack && *++invlet) continue; - invdone = 1; - } - end_menu(win, "Inventory letters used:"); - - n = select_menu(win, PICK_NONE, &selected); - if (n > 0) { - ret = selected[0].item.a_char; - free((genericptr_t)selected); - } else - ret = !n ? '\0' : '\033'; /* cancelled */ - } - return ret; + struct obj *otmp; + char ilet, ret = 0; + char *invlet = flags.inv_order; + int n, classcount, invdone = 0; + winid win; + anything any; + menu_item *selected; + + if (invent) { + win = create_nhwindow(NHW_MENU); + start_menu(win); + while (!invdone) { + any = zeroany; /* set all bits to zero */ + classcount = 0; + for(otmp = invent; otmp; otmp = otmp->nobj) { + ilet = otmp->invlet; + if (ilet == avoidlet) continue; + if (!flags.sortpack || otmp->oclass == *invlet) { + if (flags.sortpack && !classcount) { + any = zeroany; /* zero */ + add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, + let_to_name(*invlet, FALSE), MENU_UNSELECTED); + classcount++; + } + any.a_char = ilet; + add_menu(win, obj_to_glyph(otmp), + &any, ilet, 0, ATR_NONE, doname(otmp), + MENU_UNSELECTED); + } + } + if (flags.sortpack && *++invlet) continue; + invdone = 1; + } + end_menu(win, "Inventory letters used:"); + + n = select_menu(win, PICK_NONE, &selected); + if (n > 0) { + ret = selected[0].item.a_char; + free((genericptr_t)selected); + } else + ret = !n ? '\0' : '\033'; /* cancelled */ + } + return ret; } /* @@ -1871,10 +1883,10 @@ count_unpaid(list) int count = 0; while (list) { - if (list->unpaid) count++; - if (Has_contents(list)) - count += count_unpaid(list->cobj); - list = list->nobj; + if (list->unpaid) count++; + if (Has_contents(list)) + count += count_unpaid(list->cobj); + list = list->nobj; } return count; } @@ -1894,17 +1906,17 @@ count_buc(list, type) int count = 0; for ( ; list; list = list->nobj) { - /* coins are "none of the above" as far as BUCX filtering goes */ - if (list->oclass == COIN_CLASS) continue; - /* priests always know bless/curse state */ - if (Role_if(PM_PRIEST)) list->bknown = 1; - - /* check whether this object matches the requested type */ - if (!list->bknown ? (type == BUC_UNKNOWN) : - list->blessed ? (type == BUC_BLESSED) : - list->cursed ? (type == BUC_CURSED) : - (type == BUC_UNCURSED)) - ++count; + /* coins are "none of the above" as far as BUCX filtering goes */ + if (list->oclass == COIN_CLASS) continue; + /* priests always know bless/curse state */ + if (Role_if(PM_PRIEST)) list->bknown = 1; + + /* check whether this object matches the requested type */ + if (!list->bknown ? (type == BUC_UNKNOWN) : + list->blessed ? (type == BUC_BLESSED) : + list->cursed ? (type == BUC_CURSED) : + (type == BUC_UNCURSED)) + ++count; } return count; } @@ -1913,17 +1925,17 @@ long count_contents(container, nested, quantity, everything) struct obj *container; boolean nested, /* include contents of any nested containers */ - quantity, /* count all vs count separate stacks */ - everything; /* all objects vs only unpaid objects */ + quantity, /* count all vs count separate stacks */ + everything; /* all objects vs only unpaid objects */ { struct obj *otmp; long count = 0L; for (otmp = container->cobj; otmp; otmp = otmp->nobj) { - if (nested && Has_contents(otmp)) - count += count_contents(otmp, nested, quantity, everything); - if (everything || otmp->unpaid) - count += quantity ? otmp->quan : 1L; + if (nested && Has_contents(otmp)) + count += count_contents(otmp, nested, quantity, everything); + if (everything || otmp->unpaid) + count += quantity ? otmp->quan : 1L; } return count; } @@ -1941,15 +1953,15 @@ dounpaid() count = count_unpaid(invent); if (count == 1) { - marker = (struct obj *) 0; - otmp = find_unpaid(invent, &marker); - cost = unpaid_cost(otmp, FALSE); - iflags.suppress_price++; /* suppress "(unpaid)" suffix */ - pline1(xprname(otmp, distant_name(otmp, doname), - carried(otmp) ? otmp->invlet : CONTAINED_SYM, - TRUE, cost, 0L)); - iflags.suppress_price--; - return; + marker = (struct obj *) 0; + otmp = find_unpaid(invent, &marker); + cost = unpaid_cost(otmp, FALSE); + iflags.suppress_price++; /* suppress "(unpaid)" suffix */ + pline1(xprname(otmp, distant_name(otmp, doname), + carried(otmp) ? otmp->invlet : CONTAINED_SYM, + TRUE, cost, 0L)); + iflags.suppress_price--; + return; } win = create_nhwindow(NHW_MENU); @@ -1958,63 +1970,63 @@ dounpaid() if (!flags.invlet_constant) reassign(); do { - classcount = 0; - for (otmp = invent; otmp; otmp = otmp->nobj) { - ilet = otmp->invlet; - if (otmp->unpaid) { - if (!flags.sortpack || otmp->oclass == *invlet) { - if (flags.sortpack && !classcount) { - putstr(win, 0, let_to_name(*invlet, TRUE)); - classcount++; - } - - totcost += cost = unpaid_cost(otmp, FALSE); - iflags.suppress_price++; /* suppress "(unpaid)" suffix */ - putstr(win, 0, xprname(otmp, distant_name(otmp, doname), - ilet, TRUE, cost, 0L)); - iflags.suppress_price--; - num_so_far++; - } - } - } + classcount = 0; + for (otmp = invent; otmp; otmp = otmp->nobj) { + ilet = otmp->invlet; + if (otmp->unpaid) { + if (!flags.sortpack || otmp->oclass == *invlet) { + if (flags.sortpack && !classcount) { + putstr(win, 0, let_to_name(*invlet, TRUE)); + classcount++; + } + + totcost += cost = unpaid_cost(otmp, FALSE); + iflags.suppress_price++; /* suppress "(unpaid)" suffix */ + putstr(win, 0, xprname(otmp, distant_name(otmp, doname), + ilet, TRUE, cost, 0L)); + iflags.suppress_price--; + num_so_far++; + } + } + } } while (flags.sortpack && (*++invlet)); if (count > num_so_far) { - /* something unpaid is contained */ - if (flags.sortpack) - putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE)); - /* - * Search through the container objects in the inventory for - * unpaid items. The top level inventory items have already - * been listed. - */ - for (otmp = invent; otmp; otmp = otmp->nobj) { - if (Has_contents(otmp)) { - long contcost = 0L; - - marker = (struct obj *) 0; /* haven't found any */ - while (find_unpaid(otmp->cobj, &marker)) { - totcost += cost = unpaid_cost(marker, FALSE); - contcost += cost; - if (otmp->cknown) { - iflags.suppress_price++; /* suppress "(unpaid)" sfx */ - putstr(win, 0, - xprname(marker, distant_name(marker, doname), - CONTAINED_SYM, TRUE, cost, 0L)); - iflags.suppress_price--; - } - } - if (!otmp->cknown) { - char contbuf[BUFSZ]; - - /* Shopkeeper knows what to charge for contents */ - Sprintf(contbuf, "%s contents", s_suffix(xname(otmp))); - putstr(win, 0, - xprname((struct obj *)0, contbuf, - CONTAINED_SYM, TRUE, contcost, 0L)); - } - } - } + /* something unpaid is contained */ + if (flags.sortpack) + putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE)); + /* + * Search through the container objects in the inventory for + * unpaid items. The top level inventory items have already + * been listed. + */ + for (otmp = invent; otmp; otmp = otmp->nobj) { + if (Has_contents(otmp)) { + long contcost = 0L; + + marker = (struct obj *) 0; /* haven't found any */ + while (find_unpaid(otmp->cobj, &marker)) { + totcost += cost = unpaid_cost(marker, FALSE); + contcost += cost; + if (otmp->cknown) { + iflags.suppress_price++; /* suppress "(unpaid)" sfx */ + putstr(win, 0, + xprname(marker, distant_name(marker, doname), + CONTAINED_SYM, TRUE, cost, 0L)); + iflags.suppress_price--; + } + } + if (!otmp->cknown) { + char contbuf[BUFSZ]; + + /* Shopkeeper knows what to charge for contents */ + Sprintf(contbuf, "%s contents", s_suffix(xname(otmp))); + putstr(win, 0, + xprname((struct obj *)0, contbuf, + CONTAINED_SYM, TRUE, contcost, 0L)); + } + } + } } putstr(win, 0, ""); @@ -2038,104 +2050,104 @@ this_type_only(obj) int dotypeinv() { - char c = '\0'; - int n, i = 0; - char *extra_types, types[BUFSZ]; - int class_count, oclass, unpaid_count, itemcount; - boolean billx = *u.ushops && doinvbill(0); - menu_item *pick_list; - boolean traditional = TRUE; - const char *prompt = "What type of object do you want an inventory of?"; - - if (!invent && !billx) { - You("aren't carrying anything."); - return 0; - } - unpaid_count = count_unpaid(invent); - if (flags.menu_style != MENU_TRADITIONAL) { - if (flags.menu_style == MENU_FULL || - flags.menu_style == MENU_PARTIAL) { - traditional = FALSE; - i = UNPAID_TYPES; - if (billx) i |= BILLED_TYPES; - n = query_category(prompt, invent, i, &pick_list, PICK_ONE); - if (!n) return 0; - this_type = c = pick_list[0].item.a_int; - free((genericptr_t) pick_list); - } - } - if (traditional) { - /* collect a list of classes of objects carried, for use as a prompt */ - types[0] = 0; - class_count = collect_obj_classes(types, invent, - FALSE, - (boolean FDECL((*),(OBJ_P))) 0, &itemcount); - if (unpaid_count) { - Strcat(types, "u"); - class_count++; - } - if (billx) { - Strcat(types, "x"); - class_count++; - } - /* add everything not already included; user won't see these */ - extra_types = eos(types); - *extra_types++ = '\033'; - if (!unpaid_count) *extra_types++ = 'u'; - if (!billx) *extra_types++ = 'x'; - *extra_types = '\0'; /* for index() */ - for (i = 0; i < MAXOCLASSES; i++) - if (!index(types, def_oc_syms[i].sym)) { - *extra_types++ = def_oc_syms[i].sym; - *extra_types = '\0'; - } - - if(class_count > 1) { - c = yn_function(prompt, types, '\0'); - savech(c); - if(c == '\0') { - clear_nhwindow(WIN_MESSAGE); - return 0; - } - } else { - /* only one thing to itemize */ - if (unpaid_count) - c = 'u'; - else if (billx) - c = 'x'; - else - c = types[0]; - } - } - if (c == 'x') { - if (billx) - (void) doinvbill(1); - else - pline("No used-up objects on your shopping bill."); - return 0; - } - if (c == 'u') { - if (unpaid_count) - dounpaid(); - else - You("are not carrying any unpaid objects."); - return 0; - } - if (traditional) { - oclass = def_char_to_objclass(c); /* change to object class */ - if (oclass == COIN_CLASS) { - return doprgold(); - } else if (index(types, c) > index(types, '\033')) { - You("have no such objects."); - return 0; - } - this_type = oclass; - } - if (query_objlist((char *) 0, invent, - (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT, - &pick_list, PICK_NONE, this_type_only) > 0) - free((genericptr_t)pick_list); - return 0; + char c = '\0'; + int n, i = 0; + char *extra_types, types[BUFSZ]; + int class_count, oclass, unpaid_count, itemcount; + boolean billx = *u.ushops && doinvbill(0); + menu_item *pick_list; + boolean traditional = TRUE; + const char *prompt = "What type of object do you want an inventory of?"; + + if (!invent && !billx) { + You("aren't carrying anything."); + return 0; + } + unpaid_count = count_unpaid(invent); + if (flags.menu_style != MENU_TRADITIONAL) { + if (flags.menu_style == MENU_FULL || + flags.menu_style == MENU_PARTIAL) { + traditional = FALSE; + i = UNPAID_TYPES; + if (billx) i |= BILLED_TYPES; + n = query_category(prompt, invent, i, &pick_list, PICK_ONE); + if (!n) return 0; + this_type = c = pick_list[0].item.a_int; + free((genericptr_t) pick_list); + } + } + if (traditional) { + /* collect a list of classes of objects carried, for use as a prompt */ + types[0] = 0; + class_count = collect_obj_classes(types, invent, + FALSE, + (boolean FDECL((*),(OBJ_P))) 0, &itemcount); + if (unpaid_count) { + Strcat(types, "u"); + class_count++; + } + if (billx) { + Strcat(types, "x"); + class_count++; + } + /* add everything not already included; user won't see these */ + extra_types = eos(types); + *extra_types++ = '\033'; + if (!unpaid_count) *extra_types++ = 'u'; + if (!billx) *extra_types++ = 'x'; + *extra_types = '\0'; /* for index() */ + for (i = 0; i < MAXOCLASSES; i++) + if (!index(types, def_oc_syms[i].sym)) { + *extra_types++ = def_oc_syms[i].sym; + *extra_types = '\0'; + } + + if(class_count > 1) { + c = yn_function(prompt, types, '\0'); + savech(c); + if(c == '\0') { + clear_nhwindow(WIN_MESSAGE); + return 0; + } + } else { + /* only one thing to itemize */ + if (unpaid_count) + c = 'u'; + else if (billx) + c = 'x'; + else + c = types[0]; + } + } + if (c == 'x') { + if (billx) + (void) doinvbill(1); + else + pline("No used-up objects on your shopping bill."); + return 0; + } + if (c == 'u') { + if (unpaid_count) + dounpaid(); + else + You("are not carrying any unpaid objects."); + return 0; + } + if (traditional) { + oclass = def_char_to_objclass(c); /* change to object class */ + if (oclass == COIN_CLASS) { + return doprgold(); + } else if (index(types, c) > index(types, '\033')) { + You("have no such objects."); + return 0; + } + this_type = oclass; + } + if (query_objlist((char *) 0, invent, + (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT, + &pick_list, PICK_NONE, this_type_only) > 0) + free((genericptr_t)pick_list); + return 0; } /* return a string describing the dungeon feature at if there @@ -2145,65 +2157,65 @@ dfeature_at(x, y, buf) int x, y; char *buf; { - struct rm *lev = &levl[x][y]; - int ltyp = lev->typ, cmap = -1; - const char *dfeature = 0; - static char altbuf[BUFSZ]; - - if (IS_DOOR(ltyp)) { - switch (lev->doormask) { - case D_NODOOR: cmap = S_ndoor; break; /* "doorway" */ - case D_ISOPEN: cmap = S_vodoor; break; /* "open door" */ - case D_BROKEN: dfeature = "broken door"; break; - default: cmap = S_vcdoor; break; /* "closed door" */ - } - /* override door description for open drawbridge */ - if (is_drawbridge_wall(x, y) >= 0) - dfeature = "open drawbridge portcullis", cmap = -1; - } else if (IS_FOUNTAIN(ltyp)) - cmap = S_fountain; /* "fountain" */ - else if (IS_THRONE(ltyp)) - cmap = S_throne; /* "opulent throne" */ - else if (is_lava(x,y)) - cmap = S_lava; /* "molten lava" */ - else if (is_ice(x,y)) - cmap = S_ice; /* "ice" */ - else if (is_pool(x,y)) - dfeature = "pool of water"; - else if (IS_SINK(ltyp)) - cmap = S_sink; /* "sink" */ - else if (IS_ALTAR(ltyp)) { - Sprintf(altbuf, "%saltar to %s (%s)", - ((lev->altarmask & AM_SHRINE) && - (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) ? - "high " : "", - a_gname(), - align_str(Amask2align(lev->altarmask & ~AM_SHRINE))); - dfeature = altbuf; - } else if ((x == xupstair && y == yupstair) || - (x == sstairs.sx && y == sstairs.sy && sstairs.up)) - cmap = S_upstair; /* "staircase up" */ - else if ((x == xdnstair && y == ydnstair) || - (x == sstairs.sx && y == sstairs.sy && !sstairs.up)) - cmap = S_dnstair; /* "staircase down" */ - else if (x == xupladder && y == yupladder) - cmap = S_upladder; /* "ladder up" */ - else if (x == xdnladder && y == ydnladder) - cmap = S_dnladder; /* "ladder down" */ - else if (ltyp == DRAWBRIDGE_DOWN) - cmap = S_vodbridge; /* "lowered drawbridge" */ - else if (ltyp == DBWALL) - cmap = S_vcdbridge; /* "raised drawbridge" */ - else if (IS_GRAVE(ltyp)) - cmap = S_grave; /* "grave" */ - else if (ltyp == TREE) - cmap = S_tree; /* "tree" */ - else if (ltyp == IRONBARS) - dfeature = "set of iron bars"; - - if (cmap >= 0) dfeature = defsyms[cmap].explanation; - if (dfeature) Strcpy(buf, dfeature); - return dfeature; + struct rm *lev = &levl[x][y]; + int ltyp = lev->typ, cmap = -1; + const char *dfeature = 0; + static char altbuf[BUFSZ]; + + if (IS_DOOR(ltyp)) { + switch (lev->doormask) { + case D_NODOOR: cmap = S_ndoor; break; /* "doorway" */ + case D_ISOPEN: cmap = S_vodoor; break; /* "open door" */ + case D_BROKEN: dfeature = "broken door"; break; + default: cmap = S_vcdoor; break; /* "closed door" */ + } + /* override door description for open drawbridge */ + if (is_drawbridge_wall(x, y) >= 0) + dfeature = "open drawbridge portcullis", cmap = -1; + } else if (IS_FOUNTAIN(ltyp)) + cmap = S_fountain; /* "fountain" */ + else if (IS_THRONE(ltyp)) + cmap = S_throne; /* "opulent throne" */ + else if (is_lava(x,y)) + cmap = S_lava; /* "molten lava" */ + else if (is_ice(x,y)) + cmap = S_ice; /* "ice" */ + else if (is_pool(x,y)) + dfeature = "pool of water"; + else if (IS_SINK(ltyp)) + cmap = S_sink; /* "sink" */ + else if (IS_ALTAR(ltyp)) { + Sprintf(altbuf, "%saltar to %s (%s)", + ((lev->altarmask & AM_SHRINE) && + (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) ? + "high " : "", + a_gname(), + align_str(Amask2align(lev->altarmask & ~AM_SHRINE))); + dfeature = altbuf; + } else if ((x == xupstair && y == yupstair) || + (x == sstairs.sx && y == sstairs.sy && sstairs.up)) + cmap = S_upstair; /* "staircase up" */ + else if ((x == xdnstair && y == ydnstair) || + (x == sstairs.sx && y == sstairs.sy && !sstairs.up)) + cmap = S_dnstair; /* "staircase down" */ + else if (x == xupladder && y == yupladder) + cmap = S_upladder; /* "ladder up" */ + else if (x == xdnladder && y == ydnladder) + cmap = S_dnladder; /* "ladder down" */ + else if (ltyp == DRAWBRIDGE_DOWN) + cmap = S_vodbridge; /* "lowered drawbridge" */ + else if (ltyp == DBWALL) + cmap = S_vcdbridge; /* "raised drawbridge" */ + else if (IS_GRAVE(ltyp)) + cmap = S_grave; /* "grave" */ + else if (ltyp == TREE) + cmap = S_tree; /* "tree" */ + else if (ltyp == IRONBARS) + dfeature = "set of iron bars"; + + if (cmap >= 0) dfeature = defsyms[cmap].explanation; + if (dfeature) Strcpy(buf, dfeature); + return dfeature; } /* look at what is here; if there are many objects (pile_limit or more), @@ -2213,146 +2225,146 @@ look_here(obj_cnt, picked_some) int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progess */ boolean picked_some; { - struct obj *otmp; - struct trap *trap; - const char *verb = Blind ? "feel" : "see"; - const char *dfeature = (char *)0; - char fbuf[BUFSZ], fbuf2[BUFSZ]; - winid tmpwin; - boolean skip_objects, felt_cockatrice = FALSE; - - /* default pile_limit is 5; a value of 0 means "never skip" - (and 1 effectively forces "always skip") */ - skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit); - if (u.uswallow && u.ustuck) { - struct monst *mtmp = u.ustuck; - Sprintf(fbuf, "Contents of %s %s", - s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); - /* Skip "Contents of " by using fbuf index 12 */ - You("%s to %s what is lying in %s.", - Blind ? "try" : "look around", verb, &fbuf[12]); - otmp = mtmp->minvent; - if (otmp) { - for ( ; otmp; otmp = otmp->nobj) { - /* If swallower is an animal, it should have become stone but... */ - if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); - } - if (Blind) Strcpy(fbuf, "You feel"); - Strcat(fbuf,":"); - (void) display_minventory(mtmp, MINV_ALL, fbuf); - } else { - You("%s no objects here.", verb); - } - return(!!Blind); - } - if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen) - There("is %s here.", - an(defsyms[trap_to_defsym(trap->ttyp)].explanation)); - - otmp = level.objects[u.ux][u.uy]; - dfeature = dfeature_at(u.ux, u.uy, fbuf2); - if (dfeature && !strcmp(dfeature, "pool of water") && Underwater) - dfeature = 0; - - if (Blind) { - boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz); - - if (dfeature && !strncmp(dfeature, "altar ", 6)) { - /* don't say "altar" twice, dfeature has more info */ - You("try to feel what is here."); - } else { - const char *where = (Blind && !can_reach_floor(TRUE)) ? - "lying beneath you" : "lying here on the ", - *onwhat = (Blind && !can_reach_floor(TRUE)) ? - "" : surface(u.ux,u.uy); - - You("try to feel what is %s%s.", - drift ? "floating here" : where, - drift ? "" : onwhat); - } - if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy))) - dfeature = 0; /* ice already identifed */ - if (!can_reach_floor(TRUE)) { - pline("But you can't reach it!"); - return(0); - } - } - - if (dfeature) - Sprintf(fbuf, "There is %s here.", an(dfeature)); - - if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) { - if (dfeature) pline1(fbuf); - read_engr_at(u.ux, u.uy); /* Eric Backus */ - if (!skip_objects && (Blind || !dfeature)) - You("%s no objects here.", verb); - return(!!Blind); - } - /* we know there is something here */ - - if (skip_objects) { - if (dfeature) pline1(fbuf); - read_engr_at(u.ux, u.uy); /* Eric Backus */ - if (obj_cnt == 1 && otmp->quan == 1L) - There("is %s object here.", picked_some ? "another" : "an"); - else - There("are %s%s objects here.", - (obj_cnt < 5) ? "a few" : - (obj_cnt < 10) ? "several" : "many", - picked_some ? " more" : ""); - for ( ; otmp; otmp = otmp->nexthere) - if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { - pline("%s %s%s.", - (obj_cnt > 1) ? "Including" : - (otmp->quan > 1L) ? "They're" : "It's", - corpse_xname(otmp, (const char *)0, CXN_ARTICLE), - poly_when_stoned(youmonst.data) ? "" : - ", unfortunately"); - feel_cockatrice(otmp, FALSE); - break; - } - } else if (!otmp->nexthere) { - /* only one object */ - if (dfeature) pline1(fbuf); - read_engr_at(u.ux, u.uy); /* Eric Backus */ - You("%s here %s.", verb, doname(otmp)); - iflags.last_msg = PLNMSG_ONE_ITEM_HERE; - if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); - } else { - char buf[BUFSZ]; - - display_nhwindow(WIN_MESSAGE, FALSE); - tmpwin = create_nhwindow(NHW_MENU); - if(dfeature) { - putstr(tmpwin, 0, fbuf); - putstr(tmpwin, 0, ""); - } - Sprintf(buf, "%s that %s here:", - picked_some ? "Other things" : "Things", - Blind ? "you feel" : "are"); - putstr(tmpwin, 0, buf); - for ( ; otmp; otmp = otmp->nexthere) { - if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { - felt_cockatrice = TRUE; - Sprintf(buf, "%s...", doname(otmp)); - putstr(tmpwin, 0, buf); - break; - } - putstr(tmpwin, 0, doname(otmp)); - } - display_nhwindow(tmpwin, TRUE); - destroy_nhwindow(tmpwin); - if (felt_cockatrice) feel_cockatrice(otmp, FALSE); - read_engr_at(u.ux, u.uy); /* Eric Backus */ - } - return(!!Blind); + struct obj *otmp; + struct trap *trap; + const char *verb = Blind ? "feel" : "see"; + const char *dfeature = (char *)0; + char fbuf[BUFSZ], fbuf2[BUFSZ]; + winid tmpwin; + boolean skip_objects, felt_cockatrice = FALSE; + + /* default pile_limit is 5; a value of 0 means "never skip" + (and 1 effectively forces "always skip") */ + skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit); + if (u.uswallow && u.ustuck) { + struct monst *mtmp = u.ustuck; + Sprintf(fbuf, "Contents of %s %s", + s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); + /* Skip "Contents of " by using fbuf index 12 */ + You("%s to %s what is lying in %s.", + Blind ? "try" : "look around", verb, &fbuf[12]); + otmp = mtmp->minvent; + if (otmp) { + for ( ; otmp; otmp = otmp->nobj) { + /* If swallower is an animal, it should have become stone but... */ + if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); + } + if (Blind) Strcpy(fbuf, "You feel"); + Strcat(fbuf,":"); + (void) display_minventory(mtmp, MINV_ALL, fbuf); + } else { + You("%s no objects here.", verb); + } + return(!!Blind); + } + if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen) + There("is %s here.", + an(defsyms[trap_to_defsym(trap->ttyp)].explanation)); + + otmp = level.objects[u.ux][u.uy]; + dfeature = dfeature_at(u.ux, u.uy, fbuf2); + if (dfeature && !strcmp(dfeature, "pool of water") && Underwater) + dfeature = 0; + + if (Blind) { + boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz); + + if (dfeature && !strncmp(dfeature, "altar ", 6)) { + /* don't say "altar" twice, dfeature has more info */ + You("try to feel what is here."); + } else { + const char *where = (Blind && !can_reach_floor(TRUE)) ? + "lying beneath you" : "lying here on the ", + *onwhat = (Blind && !can_reach_floor(TRUE)) ? + "" : surface(u.ux,u.uy); + + You("try to feel what is %s%s.", + drift ? "floating here" : where, + drift ? "" : onwhat); + } + if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy))) + dfeature = 0; /* ice already identifed */ + if (!can_reach_floor(TRUE)) { + pline("But you can't reach it!"); + return(0); + } + } + + if (dfeature) + Sprintf(fbuf, "There is %s here.", an(dfeature)); + + if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) { + if (dfeature) pline1(fbuf); + read_engr_at(u.ux, u.uy); /* Eric Backus */ + if (!skip_objects && (Blind || !dfeature)) + You("%s no objects here.", verb); + return(!!Blind); + } + /* we know there is something here */ + + if (skip_objects) { + if (dfeature) pline1(fbuf); + read_engr_at(u.ux, u.uy); /* Eric Backus */ + if (obj_cnt == 1 && otmp->quan == 1L) + There("is %s object here.", picked_some ? "another" : "an"); + else + There("are %s%s objects here.", + (obj_cnt < 5) ? "a few" : + (obj_cnt < 10) ? "several" : "many", + picked_some ? " more" : ""); + for ( ; otmp; otmp = otmp->nexthere) + if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { + pline("%s %s%s.", + (obj_cnt > 1) ? "Including" : + (otmp->quan > 1L) ? "They're" : "It's", + corpse_xname(otmp, (const char *)0, CXN_ARTICLE), + poly_when_stoned(youmonst.data) ? "" : + ", unfortunately"); + feel_cockatrice(otmp, FALSE); + break; + } + } else if (!otmp->nexthere) { + /* only one object */ + if (dfeature) pline1(fbuf); + read_engr_at(u.ux, u.uy); /* Eric Backus */ + You("%s here %s.", verb, doname(otmp)); + iflags.last_msg = PLNMSG_ONE_ITEM_HERE; + if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); + } else { + char buf[BUFSZ]; + + display_nhwindow(WIN_MESSAGE, FALSE); + tmpwin = create_nhwindow(NHW_MENU); + if(dfeature) { + putstr(tmpwin, 0, fbuf); + putstr(tmpwin, 0, ""); + } + Sprintf(buf, "%s that %s here:", + picked_some ? "Other things" : "Things", + Blind ? "you feel" : "are"); + putstr(tmpwin, 0, buf); + for ( ; otmp; otmp = otmp->nexthere) { + if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { + felt_cockatrice = TRUE; + Sprintf(buf, "%s...", doname(otmp)); + putstr(tmpwin, 0, buf); + break; + } + putstr(tmpwin, 0, doname(otmp)); + } + display_nhwindow(tmpwin, TRUE); + destroy_nhwindow(tmpwin); + if (felt_cockatrice) feel_cockatrice(otmp, FALSE); + read_engr_at(u.ux, u.uy); /* Eric Backus */ + } + return(!!Blind); } /* explicilty look at what is here, including all objects */ int dolook() { - return look_here(0, FALSE); + return look_here(0, FALSE); } boolean @@ -2360,11 +2372,11 @@ will_feel_cockatrice(otmp, force_touch) struct obj *otmp; boolean force_touch; { - if ((Blind || force_touch) && !uarmg && !Stone_resistance && - (otmp->otyp == CORPSE && - touch_petrifies(&mons[otmp->corpsenm]))) - return TRUE; - return FALSE; + if ((Blind || force_touch) && !uarmg && !Stone_resistance && + (otmp->otyp == CORPSE && + touch_petrifies(&mons[otmp->corpsenm]))) + return TRUE; + return FALSE; } void @@ -2372,138 +2384,138 @@ feel_cockatrice(otmp, force_touch) struct obj *otmp; boolean force_touch; { - char kbuf[BUFSZ]; - - if (will_feel_cockatrice(otmp, force_touch)) { - /* "the corpse" */ - Strcpy(kbuf, corpse_xname(otmp, (const char *)0, CXN_PFX_THE)); - - if (poly_when_stoned(youmonst.data)) - You("touched %s with your bare %s.", - kbuf, makeplural(body_part(HAND))); - else - pline("Touching %s is a fatal mistake...", kbuf); - /* normalize body shape here; hand, not body_part(HAND) */ - Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp)); - /* will call polymon() for the poly_when_stoned() case */ - instapetrify(kbuf); - } + char kbuf[BUFSZ]; + + if (will_feel_cockatrice(otmp, force_touch)) { + /* "the corpse" */ + Strcpy(kbuf, corpse_xname(otmp, (const char *)0, CXN_PFX_THE)); + + if (poly_when_stoned(youmonst.data)) + You("touched %s with your bare %s.", + kbuf, makeplural(body_part(HAND))); + else + pline("Touching %s is a fatal mistake...", kbuf); + /* normalize body shape here; hand, not body_part(HAND) */ + Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp)); + /* will call polymon() for the poly_when_stoned() case */ + instapetrify(kbuf); + } } void stackobj(obj) struct obj *obj; { - struct obj *otmp; + struct obj *otmp; - for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere) - if(otmp != obj && merged(&obj,&otmp)) - break; - return; + for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere) + if(otmp != obj && merged(&obj,&otmp)) + break; + return; } STATIC_OVL boolean mergable(otmp, obj) /* returns TRUE if obj & otmp can be merged */ - register struct obj *otmp, *obj; -{ - int objnamelth = 0, otmpnamelth = 0; - if (obj->otyp != otmp->otyp) return FALSE; - /* coins of the same kind will always merge */ - if (obj->oclass == COIN_CLASS) return TRUE; - if (obj->unpaid != otmp->unpaid || - obj->spe != otmp->spe || obj->dknown != otmp->dknown || - (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) || - obj->cursed != otmp->cursed || obj->blessed != otmp->blessed || - obj->no_charge != otmp->no_charge || - obj->obroken != otmp->obroken || - obj->otrapped != otmp->otrapped || - obj->lamplit != otmp->lamplit || - obj->greased != otmp->greased || - obj->oeroded != otmp->oeroded || - obj->oeroded2 != otmp->oeroded2 || - obj->bypass != otmp->bypass) - return(FALSE); - - if (obj->nomerge) /* explicitly marked to prevent merge */ - return FALSE; - - if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) && - (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown)) - return FALSE; - - if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten || - obj->orotten != otmp->orotten)) - return(FALSE); - - if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) { - if (obj->corpsenm != otmp->corpsenm) - return FALSE; - } - - /* hatching eggs don't merge; ditto for revivable corpses */ - if ((obj->otyp == EGG && (obj->timed || otmp->timed)) || - (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM && - is_reviver(&mons[otmp->corpsenm]))) - return FALSE; - - /* allow candle merging only if their ages are close */ - /* see begin_burn() for a reference for the magic "25" */ - if (Is_candle(obj) && obj->age/25 != otmp->age/25) - return(FALSE); - - /* burning potions of oil never merge */ - if (obj->otyp == POT_OIL && obj->lamplit) - return FALSE; - - /* don't merge surcharged item with base-cost item */ - if (obj->unpaid && !same_price(obj, otmp)) - return FALSE; - - /* if they have names, make sure they're the same */ - objnamelth = strlen(safe_oname(obj)); - otmpnamelth = strlen(safe_oname(otmp)); - if ( (objnamelth != otmpnamelth && - ((objnamelth && otmpnamelth) || obj->otyp == CORPSE) - ) || - (objnamelth && otmpnamelth && - strncmp(ONAME(obj), ONAME(otmp), objnamelth))) - return FALSE; - - /* for the moment, any additional information is incompatible */ - if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || - has_omonst(otmp) || has_omid(otmp) || has_olong(otmp)) - return FALSE; - - if(obj->oartifact != otmp->oartifact) return FALSE; - - if(obj->known == otmp->known || - !objects[otmp->otyp].oc_uses_known) { - return((boolean)(objects[obj->otyp].oc_merge)); - } else return(FALSE); + register struct obj *otmp, *obj; +{ + int objnamelth = 0, otmpnamelth = 0; + if (obj->otyp != otmp->otyp) return FALSE; + /* coins of the same kind will always merge */ + if (obj->oclass == COIN_CLASS) return TRUE; + if (obj->unpaid != otmp->unpaid || + obj->spe != otmp->spe || obj->dknown != otmp->dknown || + (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) || + obj->cursed != otmp->cursed || obj->blessed != otmp->blessed || + obj->no_charge != otmp->no_charge || + obj->obroken != otmp->obroken || + obj->otrapped != otmp->otrapped || + obj->lamplit != otmp->lamplit || + obj->greased != otmp->greased || + obj->oeroded != otmp->oeroded || + obj->oeroded2 != otmp->oeroded2 || + obj->bypass != otmp->bypass) + return(FALSE); + + if (obj->nomerge) /* explicitly marked to prevent merge */ + return FALSE; + + if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) && + (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown)) + return FALSE; + + if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten || + obj->orotten != otmp->orotten)) + return(FALSE); + + if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) { + if (obj->corpsenm != otmp->corpsenm) + return FALSE; + } + + /* hatching eggs don't merge; ditto for revivable corpses */ + if ((obj->otyp == EGG && (obj->timed || otmp->timed)) || + (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM && + is_reviver(&mons[otmp->corpsenm]))) + return FALSE; + + /* allow candle merging only if their ages are close */ + /* see begin_burn() for a reference for the magic "25" */ + if (Is_candle(obj) && obj->age/25 != otmp->age/25) + return(FALSE); + + /* burning potions of oil never merge */ + if (obj->otyp == POT_OIL && obj->lamplit) + return FALSE; + + /* don't merge surcharged item with base-cost item */ + if (obj->unpaid && !same_price(obj, otmp)) + return FALSE; + + /* if they have names, make sure they're the same */ + objnamelth = strlen(safe_oname(obj)); + otmpnamelth = strlen(safe_oname(otmp)); + if ( (objnamelth != otmpnamelth && + ((objnamelth && otmpnamelth) || obj->otyp == CORPSE) + ) || + (objnamelth && otmpnamelth && + strncmp(ONAME(obj), ONAME(otmp), objnamelth))) + return FALSE; + + /* for the moment, any additional information is incompatible */ + if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || + has_omonst(otmp) || has_omid(otmp) || has_olong(otmp)) + return FALSE; + + if(obj->oartifact != otmp->oartifact) return FALSE; + + if(obj->known == otmp->known || + !objects[otmp->otyp].oc_uses_known) { + return((boolean)(objects[obj->otyp].oc_merge)); + } else return(FALSE); } int doprgold() { - /* the messages used to refer to "carrying gold", but that didn't - take containers into account */ + /* the messages used to refer to "carrying gold", but that didn't + take containers into account */ long umoney = money_cnt(invent); - if(!umoney) - Your("wallet is empty."); - else - Your("wallet contains %ld %s.", umoney, currency(umoney)); - shopper_financial_report(); - return 0; + if(!umoney) + Your("wallet is empty."); + else + Your("wallet contains %ld %s.", umoney, currency(umoney)); + shopper_financial_report(); + return 0; } int doprwep() { if (!uwep) { - You("are empty %s.", body_part(HANDED)); + You("are empty %s.", body_part(HANDED)); } else { - prinv((char *)0, uwep, 0L); - if (u.twoweap) prinv((char *)0, uswapwep, 0L); + prinv((char *)0, uwep, 0L); + if (u.twoweap) prinv((char *)0, uswapwep, 0L); } return 0; } @@ -2514,95 +2526,95 @@ noarmor(report_uskin) boolean report_uskin; { if (!uskin || !report_uskin) { - You("are not wearing any armor."); + You("are not wearing any armor."); } else { - char *p, *uskinname, buf[BUFSZ]; + char *p, *uskinname, buf[BUFSZ]; - uskinname = strcpy(buf, simpleonames(uskin)); - /* shorten "set of dragon scales" to " scales" - and " dragon scale mail" to " scale mail" */ - if (!strncmpi(uskinname, "set of ", 7)) uskinname += 7; - if ((p = strstri(uskinname, " dragon ")) != 0) - while ((p[1] = p[8]) != '\0') ++p; + uskinname = strcpy(buf, simpleonames(uskin)); + /* shorten "set of dragon scales" to " scales" + and " dragon scale mail" to " scale mail" */ + if (!strncmpi(uskinname, "set of ", 7)) uskinname += 7; + if ((p = strstri(uskinname, " dragon ")) != 0) + while ((p[1] = p[8]) != '\0') ++p; - You("are not wearing armor but have %s embedded in your skin.", - uskinname); + You("are not wearing armor but have %s embedded in your skin.", + uskinname); } } int doprarm() { - if (!wearing_armor()) { - noarmor(TRUE); - } else { - char lets[8]; - register int ct = 0; - - if(uarmu) lets[ct++] = obj_to_let(uarmu); - if(uarm) lets[ct++] = obj_to_let(uarm); - if(uarmc) lets[ct++] = obj_to_let(uarmc); - if(uarmh) lets[ct++] = obj_to_let(uarmh); - if(uarms) lets[ct++] = obj_to_let(uarms); - if(uarmg) lets[ct++] = obj_to_let(uarmg); - if(uarmf) lets[ct++] = obj_to_let(uarmf); - lets[ct] = 0; - (void) display_inventory(lets, FALSE); - } - return 0; + if (!wearing_armor()) { + noarmor(TRUE); + } else { + char lets[8]; + register int ct = 0; + + if(uarmu) lets[ct++] = obj_to_let(uarmu); + if(uarm) lets[ct++] = obj_to_let(uarm); + if(uarmc) lets[ct++] = obj_to_let(uarmc); + if(uarmh) lets[ct++] = obj_to_let(uarmh); + if(uarms) lets[ct++] = obj_to_let(uarms); + if(uarmg) lets[ct++] = obj_to_let(uarmg); + if(uarmf) lets[ct++] = obj_to_let(uarmf); + lets[ct] = 0; + (void) display_inventory(lets, FALSE); + } + return 0; } int doprring() { - if(!uleft && !uright) - You("are not wearing any rings."); - else { - char lets[3]; - register int ct = 0; + if(!uleft && !uright) + You("are not wearing any rings."); + else { + char lets[3]; + register int ct = 0; - if(uleft) lets[ct++] = obj_to_let(uleft); - if(uright) lets[ct++] = obj_to_let(uright); - lets[ct] = 0; - (void) display_inventory(lets, FALSE); - } - return 0; + if(uleft) lets[ct++] = obj_to_let(uleft); + if(uright) lets[ct++] = obj_to_let(uright); + lets[ct] = 0; + (void) display_inventory(lets, FALSE); + } + return 0; } int dopramulet() { - if (!uamul) - You("are not wearing an amulet."); - else - prinv((char *)0, uamul, 0L); - return 0; + if (!uamul) + You("are not wearing an amulet."); + else + prinv((char *)0, uamul, 0L); + return 0; } STATIC_OVL boolean tool_in_use(obj) struct obj *obj; { - if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L) return TRUE; - if (obj->oclass != TOOL_CLASS) return FALSE; - return (boolean)(obj == uwep || obj->lamplit || - (obj->otyp == LEASH && obj->leashmon)); + if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L) return TRUE; + if (obj->oclass != TOOL_CLASS) return FALSE; + return (boolean)(obj == uwep || obj->lamplit || + (obj->otyp == LEASH && obj->leashmon)); } int doprtool() { - struct obj *otmp; - int ct = 0; - char lets[52+1]; - - for (otmp = invent; otmp; otmp = otmp->nobj) - if (tool_in_use(otmp)) - lets[ct++] = obj_to_let(otmp); - lets[ct] = '\0'; - if (!ct) You("are not using any tools."); - else (void) display_inventory(lets, FALSE); - return 0; + struct obj *otmp; + int ct = 0; + char lets[52+1]; + + for (otmp = invent; otmp; otmp = otmp->nobj) + if (tool_in_use(otmp)) + lets[ct++] = obj_to_let(otmp); + lets[ct] = '\0'; + if (!ct) You("are not using any tools."); + else (void) display_inventory(lets, FALSE); + return 0; } /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands; @@ -2610,17 +2622,17 @@ doprtool() int doprinuse() { - struct obj *otmp; - int ct = 0; - char lets[52+1]; - - for (otmp = invent; otmp; otmp = otmp->nobj) - if (is_worn(otmp) || tool_in_use(otmp)) - lets[ct++] = obj_to_let(otmp); - lets[ct] = '\0'; - if (!ct) You("are not wearing or wielding anything."); - else (void) display_inventory(lets, FALSE); - return 0; + struct obj *otmp; + int ct = 0; + char lets[52+1]; + + for (otmp = invent; otmp; otmp = otmp->nobj) + if (is_worn(otmp) || tool_in_use(otmp)) + lets[ct++] = obj_to_let(otmp); + lets[ct] = '\0'; + if (!ct) You("are not wearing or wielding anything."); + else (void) display_inventory(lets, FALSE); + return 0; } /* @@ -2631,23 +2643,23 @@ useupf(obj, numused) register struct obj *obj; long numused; { - register struct obj *otmp; - boolean at_u = (obj->ox == u.ux && obj->oy == u.uy); - - /* burn_floor_paper() keeps an object pointer that it tries to - * useupf() multiple times, so obj must survive if plural */ - if (obj->quan > numused) - otmp = splitobj(obj, numused); - else - otmp = obj; - if(costly_spot(otmp->ox, otmp->oy)) { - if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0))) - addtobill(otmp, FALSE, FALSE, FALSE); - else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE); - } - delobj(otmp); - if (at_u && u.uundetected && hides_under(youmonst.data)) - (void) hideunder(&youmonst); + register struct obj *otmp; + boolean at_u = (obj->ox == u.ux && obj->oy == u.uy); + + /* burn_floor_paper() keeps an object pointer that it tries to + * useupf() multiple times, so obj must survive if plural */ + if (obj->quan > numused) + otmp = splitobj(obj, numused); + else + otmp = obj; + if(costly_spot(otmp->ox, otmp->oy)) { + if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0))) + addtobill(otmp, FALSE, FALSE, FALSE); + else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE); + } + delobj(otmp); + if (at_u && u.uundetected && hides_under(youmonst.data)) + (void) hideunder(&youmonst); } /* @@ -2655,19 +2667,19 @@ long numused; * This must match the object class order. */ STATIC_VAR NEARDATA const char *names[] = { 0, - "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", - "Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks", - "Wands", "Coins", "Gems/Stones", "Boulders/Statues", "Iron balls", - "Chains", "Venoms" + "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", + "Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks", + "Wands", "Coins", "Gems/Stones", "Boulders/Statues", "Iron balls", + "Chains", "Venoms" }; static NEARDATA const char oth_symbols[] = { - CONTAINED_SYM, - '\0' + CONTAINED_SYM, + '\0' }; static NEARDATA const char *oth_names[] = { - "Bagged/Boxed items" + "Bagged/Boxed items" }; static NEARDATA char *invbuf = (char *)0; @@ -2678,59 +2690,59 @@ let_to_name(let,unpaid) char let; boolean unpaid; { - const char *class_name; - const char *pos; - int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0; - unsigned len; - - if (oclass) - class_name = names[oclass]; - else if ((pos = index(oth_symbols, let)) != 0) - class_name = oth_names[pos - oth_symbols]; - else - class_name = names[0]; - - len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof ""); - if (len > invbufsiz) { - if (invbuf) free((genericptr_t)invbuf); - invbufsiz = len + 10; /* add slop to reduce incremental realloc */ - invbuf = (char *) alloc(invbufsiz); - } - if (unpaid) - Strcat(strcpy(invbuf, "Unpaid "), class_name); - else - Strcpy(invbuf, class_name); - return invbuf; + const char *class_name; + const char *pos; + int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0; + unsigned len; + + if (oclass) + class_name = names[oclass]; + else if ((pos = index(oth_symbols, let)) != 0) + class_name = oth_names[pos - oth_symbols]; + else + class_name = names[0]; + + len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof ""); + if (len > invbufsiz) { + if (invbuf) free((genericptr_t)invbuf); + invbufsiz = len + 10; /* add slop to reduce incremental realloc */ + invbuf = (char *) alloc(invbufsiz); + } + if (unpaid) + Strcat(strcpy(invbuf, "Unpaid "), class_name); + else + Strcpy(invbuf, class_name); + return invbuf; } /* release the static buffer used by let_to_name() */ void free_invbuf() { - if (invbuf) free((genericptr_t)invbuf), invbuf = (char *)0; - invbufsiz = 0; + if (invbuf) free((genericptr_t)invbuf), invbuf = (char *)0; + invbufsiz = 0; } /* give consecutive letters to every item in inventory (for !fixinv mode) */ void reassign() { - register int i; - register struct obj *obj; - - for(obj = invent, i = 0; obj; obj = obj->nobj, i++) { - if (obj->oclass == COIN_CLASS && obj->invlet == GOLD_SYM) - --i; /* keep $ instead of using up i'th letter */ - else - if (i < 52) - obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26); - else if (obj->oclass == COIN_CLASS) - obj->invlet = GOLD_SYM; - else - obj->invlet = NOINVSYM; - } - if (i >= 52) i = 52 - 1; - lastinvnr = i; + register int i; + register struct obj *obj; + + for(obj = invent, i = 0; obj; obj = obj->nobj, i++) { + if (obj->oclass == COIN_CLASS && obj->invlet == GOLD_SYM) + --i; /* keep $ instead of using up i'th letter */ + else + if (i < 52) + obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26); + else if (obj->oclass == COIN_CLASS) + obj->invlet = GOLD_SYM; + else + obj->invlet = NOINVSYM; + } + if (i >= 52) i = 52 - 1; + lastinvnr = i; } /* #adjust command @@ -2760,169 +2772,169 @@ reassign() int doorganize() /* inventory organizer by Del Lamb */ { - struct obj *obj, *otmp, *splitting, *bumped; - int ix, cur, trycnt; - char let; - char alphabet[52+1], buf[52+1]; - char qbuf[QBUFSZ]; - char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */ - const char *adj_type; - - if (!invent) { - You("aren't carrying anything to adjust."); - return 0; - } - - if (!flags.invlet_constant) reassign(); - /* get object the user wants to organize (the 'from' slot) */ - allowall[0] = ALLOW_COUNT; - allowall[1] = ALL_CLASSES; - allowall[2] = '\0'; - if (!(obj = getobj(allowall,"adjust"))) return(0); - - /* figure out whether user gave a split count to getobj() */ - splitting = bumped = 0; - for (otmp = invent; otmp; otmp = otmp->nobj) - if (otmp->nobj == obj) { /* knowledge of splitobj() operation */ - if (otmp->invlet == obj->invlet) splitting = otmp; - break; - } - - /* initialize the list with all lower and upper case letters */ - for (ix = 0, let = 'a'; let <= 'z'; ) alphabet[ix++] = let++; - for (let = 'A'; let <= 'Z'; ) alphabet[ix++] = let++; - alphabet[ix] = '\0'; - /* for floating inv letters, truncate list after the first open slot */ - if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52) - alphabet[ix + (splitting ? 0 : 1)] = '\0'; - - /* blank out all the letters currently in use in the inventory */ - /* except those that will be merged with the selected object */ - for (otmp = invent; otmp; otmp = otmp->nobj) - if (otmp != obj && !mergable(otmp, obj)) { - let = otmp->invlet; - if (let >= 'a' && let <= 'z') - alphabet[let - 'a'] = ' '; - else if (let >= 'A' && let <= 'Z') - alphabet[let - 'A' + 26] = ' '; - } - - /* compact the list by removing all the blanks */ - for (ix = cur = 0; alphabet[ix]; ix++) - if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix]; - if (!cur && obj->invlet == NOINVSYM) buf[cur++] = NOINVSYM; - buf[cur] = '\0'; - /* and by dashing runs of letters */ - if(cur > 5) compactify(buf); - - /* get 'to' slot to use as destination */ - Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf, - invent ? " (? see used letters)" : ""); - for (trycnt = 1; ; ++trycnt) { - let = yn_function(qbuf, (char *)0, '\0'); - if(let == '?' || let == '*') { - let = display_used_invlets(splitting ? obj->invlet : 0); - if (!let) continue; - if (let == '\033') goto noadjust; - } - if (index(quitchars, let) || - /* adjusting to same slot is meaningful since all - compatible stacks get collected along the way, - but splitting to same slot is not */ - (splitting && let == obj->invlet)) { + struct obj *obj, *otmp, *splitting, *bumped; + int ix, cur, trycnt; + char let; + char alphabet[52+1], buf[52+1]; + char qbuf[QBUFSZ]; + char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */ + const char *adj_type; + + if (!invent) { + You("aren't carrying anything to adjust."); + return 0; + } + + if (!flags.invlet_constant) reassign(); + /* get object the user wants to organize (the 'from' slot) */ + allowall[0] = ALLOW_COUNT; + allowall[1] = ALL_CLASSES; + allowall[2] = '\0'; + if (!(obj = getobj(allowall,"adjust"))) return(0); + + /* figure out whether user gave a split count to getobj() */ + splitting = bumped = 0; + for (otmp = invent; otmp; otmp = otmp->nobj) + if (otmp->nobj == obj) { /* knowledge of splitobj() operation */ + if (otmp->invlet == obj->invlet) splitting = otmp; + break; + } + + /* initialize the list with all lower and upper case letters */ + for (ix = 0, let = 'a'; let <= 'z'; ) alphabet[ix++] = let++; + for (let = 'A'; let <= 'Z'; ) alphabet[ix++] = let++; + alphabet[ix] = '\0'; + /* for floating inv letters, truncate list after the first open slot */ + if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52) + alphabet[ix + (splitting ? 0 : 1)] = '\0'; + + /* blank out all the letters currently in use in the inventory */ + /* except those that will be merged with the selected object */ + for (otmp = invent; otmp; otmp = otmp->nobj) + if (otmp != obj && !mergable(otmp, obj)) { + let = otmp->invlet; + if (let >= 'a' && let <= 'z') + alphabet[let - 'a'] = ' '; + else if (let >= 'A' && let <= 'Z') + alphabet[let - 'A' + 26] = ' '; + } + + /* compact the list by removing all the blanks */ + for (ix = cur = 0; alphabet[ix]; ix++) + if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix]; + if (!cur && obj->invlet == NOINVSYM) buf[cur++] = NOINVSYM; + buf[cur] = '\0'; + /* and by dashing runs of letters */ + if(cur > 5) compactify(buf); + + /* get 'to' slot to use as destination */ + Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf, + invent ? " (? see used letters)" : ""); + for (trycnt = 1; ; ++trycnt) { + let = yn_function(qbuf, (char *)0, '\0'); + if(let == '?' || let == '*') { + let = display_used_invlets(splitting ? obj->invlet : 0); + if (!let) continue; + if (let == '\033') goto noadjust; + } + if (index(quitchars, let) || + /* adjusting to same slot is meaningful since all + compatible stacks get collected along the way, + but splitting to same slot is not */ + (splitting && let == obj->invlet)) { noadjust: - if (splitting) (void) merged(&splitting, &obj); - pline1(Never_mind); - return 0; - } - if ((letter(let) && let != '@') || index(buf, let)) - break; /* got one */ - if (trycnt == 5) goto noadjust; - pline("Select an inventory slot letter."); /* else try again */ - } - - /* change the inventory and print the resulting item */ - adj_type = !splitting ? "Moving:" : "Splitting:"; - - /* - * don't use freeinv/addinv to avoid double-touching artifacts, - * dousing lamps, losing luck, cursing loadstone, etc. - */ - extract_nobj(obj, &invent); - - for (otmp = invent; otmp; ) { - if (!splitting) { - if (merged(&otmp, &obj)) { - adj_type = "Merging:"; - obj = otmp; - otmp = otmp->nobj; - extract_nobj(obj, &invent); - continue; /* otmp has already been updated */ - } else if (otmp->invlet == let) { - adj_type = "Swapping:"; - otmp->invlet = obj->invlet; - } - } else { - /* splitting: don't merge extra compatible stacks; - if destination is compatible, do merge with it, - otherwise bump whatever is there to an open slot */ - if (otmp->invlet == let) { - int olth = 0; - - if (has_oname(obj)) olth = strlen(ONAME(obj)); - /* ugly hack: if these objects aren't going to merge - solely because they have conflicting user-assigned - names, strip off the name of the one being moved */ - if (olth && !obj->oartifact && !mergable(otmp, obj)) { - char *holdname = ONAME(obj); - ONAME(obj) = (char *)0; - /* restore name iff merging is still not possible */ - if (!mergable(otmp, obj)) { - ONAME(obj) = holdname; - holdname = (char *)0; - } else free((genericptr_t)holdname); - } - - if (merged(&otmp, &obj)) { - obj = otmp; - extract_nobj(obj, &invent); - } else if (inv_cnt(FALSE) >= 52) { - (void) merged(&splitting, &obj); /* undo split */ - /* "knapsack cannot accommodate any more items" */ - Your("pack is too full."); - return 0; - } else { - bumped = otmp; - extract_nobj(bumped, &invent); - } - break; - } /* found 'to' slot */ - } /* splitting */ - otmp = otmp->nobj; - } - - /* inline addinv; insert loose object at beginning of inventory */ - obj->invlet = let; - obj->nobj = invent; - obj->where = OBJ_INVENT; - invent = obj; - reorder_invent(); - if (bumped) { - /* splitting the 'from' stack is causing an incompatible - stack in the 'to' slot to be moved into an open one; - we need to do another inline insertion to inventory */ - assigninvlet(bumped); - bumped->nobj = invent; - bumped->where = OBJ_INVENT; - invent = bumped; - reorder_invent(); - } - - /* messages deferred until inventory has been fully reestablished */ - prinv(adj_type, obj, 0L); - if (bumped) prinv("Moving:", bumped, 0L); - update_inventory(); - return(0); + if (splitting) (void) merged(&splitting, &obj); + pline1(Never_mind); + return 0; + } + if ((letter(let) && let != '@') || index(buf, let)) + break; /* got one */ + if (trycnt == 5) goto noadjust; + pline("Select an inventory slot letter."); /* else try again */ + } + + /* change the inventory and print the resulting item */ + adj_type = !splitting ? "Moving:" : "Splitting:"; + + /* + * don't use freeinv/addinv to avoid double-touching artifacts, + * dousing lamps, losing luck, cursing loadstone, etc. + */ + extract_nobj(obj, &invent); + + for (otmp = invent; otmp; ) { + if (!splitting) { + if (merged(&otmp, &obj)) { + adj_type = "Merging:"; + obj = otmp; + otmp = otmp->nobj; + extract_nobj(obj, &invent); + continue; /* otmp has already been updated */ + } else if (otmp->invlet == let) { + adj_type = "Swapping:"; + otmp->invlet = obj->invlet; + } + } else { + /* splitting: don't merge extra compatible stacks; + if destination is compatible, do merge with it, + otherwise bump whatever is there to an open slot */ + if (otmp->invlet == let) { + int olth = 0; + + if (has_oname(obj)) olth = strlen(ONAME(obj)); + /* ugly hack: if these objects aren't going to merge + solely because they have conflicting user-assigned + names, strip off the name of the one being moved */ + if (olth && !obj->oartifact && !mergable(otmp, obj)) { + char *holdname = ONAME(obj); + ONAME(obj) = (char *)0; + /* restore name iff merging is still not possible */ + if (!mergable(otmp, obj)) { + ONAME(obj) = holdname; + holdname = (char *)0; + } else free((genericptr_t)holdname); + } + + if (merged(&otmp, &obj)) { + obj = otmp; + extract_nobj(obj, &invent); + } else if (inv_cnt(FALSE) >= 52) { + (void) merged(&splitting, &obj); /* undo split */ + /* "knapsack cannot accommodate any more items" */ + Your("pack is too full."); + return 0; + } else { + bumped = otmp; + extract_nobj(bumped, &invent); + } + break; + } /* found 'to' slot */ + } /* splitting */ + otmp = otmp->nobj; + } + + /* inline addinv; insert loose object at beginning of inventory */ + obj->invlet = let; + obj->nobj = invent; + obj->where = OBJ_INVENT; + invent = obj; + reorder_invent(); + if (bumped) { + /* splitting the 'from' stack is causing an incompatible + stack in the 'to' slot to be moved into an open one; + we need to do another inline insertion to inventory */ + assigninvlet(bumped); + bumped->nobj = invent; + bumped->where = OBJ_INVENT; + invent = bumped; + reorder_invent(); + } + + /* messages deferred until inventory has been fully reestablished */ + prinv(adj_type, obj, 0L); + if (bumped) prinv("Moving:", bumped, 0L); + update_inventory(); + return(0); } /* common to display_minventory and display_cinventory */ @@ -2930,21 +2942,21 @@ STATIC_OVL void invdisp_nothing(hdr, txt) const char *hdr, *txt; { - winid win; - anything any; - menu_item *selected; + winid win; + anything any; + menu_item *selected; - any = zeroany; - win = create_nhwindow(NHW_MENU); - start_menu(win); - add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED); - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED); - end_menu(win, (char *)0); - if (select_menu(win, PICK_NONE, &selected) > 0) - free((genericptr_t)selected); - destroy_nhwindow(win); - return; + any = zeroany; + win = create_nhwindow(NHW_MENU); + start_menu(win); + add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED); + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED); + end_menu(win, (char *)0); + if (select_menu(win, PICK_NONE, &selected) > 0) + free((genericptr_t)selected); + destroy_nhwindow(win); + return; } /* query_objlist callback: return things that could possibly be worn/wielded */ @@ -2953,10 +2965,10 @@ worn_wield_only(obj) struct obj *obj; { return (obj->oclass == WEAPON_CLASS - || obj->oclass == ARMOR_CLASS - || obj->oclass == AMULET_CLASS - || obj->oclass == RING_CLASS - || obj->oclass == TOOL_CLASS); + || obj->oclass == ARMOR_CLASS + || obj->oclass == AMULET_CLASS + || obj->oclass == RING_CLASS + || obj->oclass == TOOL_CLASS); } /* @@ -2976,42 +2988,42 @@ register struct monst *mon; int dflags; char *title; { - struct obj *ret; - char tmp[QBUFSZ]; - int n; - menu_item *selected = 0; - int do_all = (dflags & MINV_ALL) != 0, - incl_hero = (do_all && u.uswallow && mon == u.ustuck), - have_inv = (mon->minvent != 0), - have_any = (have_inv || incl_hero); - - Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)), - do_all ? "possessions" : "armament"); - - if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) { - /* Fool the 'weapon in hand' routine into - * displaying 'weapon in claw', etc. properly. - */ - youmonst.data = mon->data; - - n = query_objlist(title ? title : tmp, mon->minvent, - INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0), - &selected, - (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE, - do_all ? allow_all : worn_wield_only); - - set_uasmon(); - } else { - invdisp_nothing(title ? title : tmp, "(none)"); - n = 0; - } - - if (n > 0) { - ret = selected[0].item.a_obj; - free((genericptr_t)selected); - } else - ret = (struct obj *) 0; - return ret; + struct obj *ret; + char tmp[QBUFSZ]; + int n; + menu_item *selected = 0; + int do_all = (dflags & MINV_ALL) != 0, + incl_hero = (do_all && u.uswallow && mon == u.ustuck), + have_inv = (mon->minvent != 0), + have_any = (have_inv || incl_hero); + + Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)), + do_all ? "possessions" : "armament"); + + if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) { + /* Fool the 'weapon in hand' routine into + * displaying 'weapon in claw', etc. properly. + */ + youmonst.data = mon->data; + + n = query_objlist(title ? title : tmp, mon->minvent, + INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0), + &selected, + (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE, + do_all ? allow_all : worn_wield_only); + + set_uasmon(); + } else { + invdisp_nothing(title ? title : tmp, "(none)"); + n = 0; + } + + if (n > 0) { + ret = selected[0].item.a_obj; + free((genericptr_t)selected); + } else + ret = (struct obj *) 0; + return ret; } /* @@ -3022,28 +3034,28 @@ struct obj * display_cinventory(obj) register struct obj *obj; { - struct obj *ret; - char qbuf[QBUFSZ]; - int n; - menu_item *selected = 0; - - (void)safe_qbuf(qbuf, "Contents of ", ":", - obj, doname, ansimpleoname, "that"); - - if (obj->cobj) { - n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected, - PICK_NONE, allow_all); - } else { - invdisp_nothing(qbuf, "(empty)"); - n = 0; - } - if (n > 0) { - ret = selected[0].item.a_obj; - free((genericptr_t)selected); - } else - ret = (struct obj *) 0; - obj->cknown = 1; - return ret; + struct obj *ret; + char qbuf[QBUFSZ]; + int n; + menu_item *selected = 0; + + (void)safe_qbuf(qbuf, "Contents of ", ":", + obj, doname, ansimpleoname, "that"); + + if (obj->cobj) { + n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected, + PICK_NONE, allow_all); + } else { + invdisp_nothing(qbuf, "(empty)"); + n = 0; + } + if (n > 0) { + ret = selected[0].item.a_obj; + free((genericptr_t)selected); + } else + ret = (struct obj *) 0; + obj->cknown = 1; + return ret; } /* query objlist callback: return TRUE if obj is at given location */ @@ -3067,27 +3079,27 @@ display_binventory(x, y, as_if_seen) int x, y; boolean as_if_seen; { - struct obj *obj; - menu_item *selected = 0; - int n; - - /* count # of objects here */ - for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj) - if (obj->ox == x && obj->oy == y) { - if (as_if_seen) obj->dknown = 1; - n++; - } - - if (n) { - only.x = x; - only.y = y; - if (query_objlist("Things that are buried here:", - level.buriedobjlist, INVORDER_SORT, - &selected, PICK_NONE, only_here) > 0) - free((genericptr_t)selected); - only.x = only.y = 0; - } - return n; + struct obj *obj; + menu_item *selected = 0; + int n; + + /* count # of objects here */ + for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj) + if (obj->ox == x && obj->oy == y) { + if (as_if_seen) obj->dknown = 1; + n++; + } + + if (n) { + only.x = x; + only.y = y; + if (query_objlist("Things that are buried here:", + level.buriedobjlist, INVORDER_SORT, + &selected, PICK_NONE, only_here) > 0) + free((genericptr_t)selected); + only.x = only.y = 0; + } + return n; } /*invent.c*/ diff --git a/src/mkobj.c b/src/mkobj.c index f909b5bd6..d9312a0f3 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -14,7 +14,7 @@ STATIC_DCL void FDECL(objlist_sanity, (struct obj *,int,const char *)); STATIC_DCL void FDECL(mon_obj_sanity, (struct monst *,const char *)); STATIC_DCL const char *FDECL(where_name, (struct obj *)); STATIC_DCL void FDECL(insane_object, - (struct obj *,const char *,const char *,struct monst *)); + (struct obj *,const char *,const char *,struct monst *)); STATIC_DCL void FDECL(check_contained, (struct obj *,const char *)); struct icp { @@ -74,92 +74,92 @@ const struct icp hellprobs[] = { struct oextra * newoextra() { - struct oextra *oextra; + struct oextra *oextra; - oextra = (struct oextra *)alloc(sizeof(struct oextra)); - oextra->oname = 0; - oextra->omonst = 0; - oextra->omid = 0; - oextra->olong = 0; - oextra->omailcmd = 0; - return oextra; + oextra = (struct oextra *)alloc(sizeof(struct oextra)); + oextra->oname = 0; + oextra->omonst = 0; + oextra->omid = 0; + oextra->olong = 0; + oextra->omailcmd = 0; + return oextra; } void dealloc_oextra(x) struct oextra *x; { - if (x) { - if (x->oname) free((genericptr_t)x->oname); - if (x->omonst) free((genericptr_t)x->omonst); - if (x->omid) free((genericptr_t)x->omid); - if (x->olong) free((genericptr_t)x->olong); - if (x->omailcmd) free((genericptr_t)x->omailcmd); - free((genericptr_t)x); - } + if (x) { + if (x->oname) free((genericptr_t)x->oname); + if (x->omonst) free((genericptr_t)x->omonst); + if (x->omid) free((genericptr_t)x->omid); + if (x->olong) free((genericptr_t)x->olong); + if (x->omailcmd) free((genericptr_t)x->omailcmd); + free((genericptr_t)x); + } } void newomonst(otmp) struct obj *otmp; { - if (!otmp->oextra) otmp->oextra = newoextra(); - if (!OMONST(otmp)) { - OMONST(otmp) = (struct monst *)alloc(sizeof(struct monst)); - (void) memset((genericptr_t) OMONST(otmp), 0, sizeof(struct monst)); - } + if (!otmp->oextra) otmp->oextra = newoextra(); + if (!OMONST(otmp)) { + OMONST(otmp) = (struct monst *)alloc(sizeof(struct monst)); + (void) memset((genericptr_t) OMONST(otmp), 0, sizeof(struct monst)); + } } void free_omonst(otmp) struct obj *otmp; { - if (otmp->oextra && OMONST(otmp)) { - free((genericptr_t) OMONST(otmp)); - OMONST(otmp) = (struct monst *)0; - } + if (otmp->oextra && OMONST(otmp)) { + free((genericptr_t) OMONST(otmp)); + OMONST(otmp) = (struct monst *)0; + } } void newomid(otmp) struct obj *otmp; { - if (!otmp->oextra) otmp->oextra = newoextra(); - if (!OMID(otmp)) { - OMID(otmp) = (unsigned *)alloc(sizeof(unsigned)); - (void) memset((genericptr_t) OMID(otmp), 0, sizeof(unsigned)); - } + if (!otmp->oextra) otmp->oextra = newoextra(); + if (!OMID(otmp)) { + OMID(otmp) = (unsigned *)alloc(sizeof(unsigned)); + (void) memset((genericptr_t) OMID(otmp), 0, sizeof(unsigned)); + } } void free_omid(otmp) struct obj *otmp; { - if (otmp->oextra && OMID(otmp)) { - free((genericptr_t) OMID(otmp)); - OMID(otmp) = (unsigned *)0; - } + if (otmp->oextra && OMID(otmp)) { + free((genericptr_t) OMID(otmp)); + OMID(otmp) = (unsigned *)0; + } } void newolong(otmp) struct obj *otmp; { - if (!otmp->oextra) otmp->oextra = newoextra(); - if (!OLONG(otmp)) { - OLONG(otmp) = (long *)alloc(sizeof(long)); - (void) memset((genericptr_t) OLONG(otmp), 0, sizeof(long)); - } + if (!otmp->oextra) otmp->oextra = newoextra(); + if (!OLONG(otmp)) { + OLONG(otmp) = (long *)alloc(sizeof(long)); + (void) memset((genericptr_t) OLONG(otmp), 0, sizeof(long)); + } } void free_olong(otmp) struct obj *otmp; { - if (otmp->oextra && OLONG(otmp)) { - free((genericptr_t) OLONG(otmp)); - OLONG(otmp) = (long *)0; - } + if (otmp->oextra && OLONG(otmp)) { + free((genericptr_t) OLONG(otmp)); + OLONG(otmp) = (long *)0; + } } void @@ -167,19 +167,19 @@ new_omailcmd(otmp, response_cmd) struct obj *otmp; const char *response_cmd; { - if (!otmp->oextra) otmp->oextra = newoextra(); - if (OMAILCMD(otmp)) free_omailcmd(otmp); - OMAILCMD(otmp) = dupstr(response_cmd); + if (!otmp->oextra) otmp->oextra = newoextra(); + if (OMAILCMD(otmp)) free_omailcmd(otmp); + OMAILCMD(otmp) = dupstr(response_cmd); } void free_omailcmd(otmp) struct obj *otmp; { - if (otmp->oextra && OMAILCMD(otmp)) { - free((genericptr_t) OMAILCMD(otmp)); - OMAILCMD(otmp) = (char *)0; - } + if (otmp->oextra && OMAILCMD(otmp)) { + free((genericptr_t) OMAILCMD(otmp)); + OMAILCMD(otmp) = (char *)0; + } } struct obj * @@ -188,11 +188,11 @@ char let; int x, y; boolean artif; { - struct obj *otmp; + struct obj *otmp; - otmp = mkobj(let, artif); - place_object(otmp, x, y); - return(otmp); + otmp = mkobj(let, artif); + place_object(otmp, x, y); + return(otmp); } struct obj * @@ -200,11 +200,11 @@ mksobj_at(otyp, x, y, init, artif) int otyp, x, y; boolean init, artif; { - struct obj *otmp; + struct obj *otmp; - otmp = mksobj(otyp, init, artif); - place_object(otmp, x, y); - return(otmp); + otmp = mksobj(otyp, init, artif); + place_object(otmp, x, y); + return(otmp); } struct obj * @@ -212,153 +212,153 @@ mkobj(oclass, artif) char oclass; boolean artif; { - int tprob, i, prob = rnd(1000); + int tprob, i, prob = rnd(1000); - if(oclass == RANDOM_CLASS) { - const struct icp *iprobs = - (Is_rogue_level(&u.uz)) ? - (const struct icp *)rogueprobs : - Inhell ? (const struct icp *)hellprobs : - (const struct icp *)mkobjprobs; + if(oclass == RANDOM_CLASS) { + const struct icp *iprobs = + (Is_rogue_level(&u.uz)) ? + (const struct icp *)rogueprobs : + Inhell ? (const struct icp *)hellprobs : + (const struct icp *)mkobjprobs; - for(tprob = rnd(100); - (tprob -= iprobs->iprob) > 0; - iprobs++); - oclass = iprobs->iclass; - } + for(tprob = rnd(100); + (tprob -= iprobs->iprob) > 0; + iprobs++); + oclass = iprobs->iclass; + } - i = bases[(int)oclass]; - while((prob -= objects[i].oc_prob) > 0) i++; + i = bases[(int)oclass]; + while((prob -= objects[i].oc_prob) > 0) i++; - if(objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) - panic("probtype error, oclass=%d i=%d", (int) oclass, i); + if(objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) + panic("probtype error, oclass=%d i=%d", (int) oclass, i); - return(mksobj(i, TRUE, artif)); + return(mksobj(i, TRUE, artif)); } STATIC_OVL void mkbox_cnts(box) struct obj *box; { - register int n; - register struct obj *otmp; - - box->cobj = (struct obj *) 0; - - switch (box->otyp) { - case ICE_BOX: n = 20; break; - case CHEST: n = 5; break; - case LARGE_BOX: n = 3; break; - case SACK: - case OILSKIN_SACK: - /* initial inventory: sack starts out empty */ - if (moves <= 1 && !in_mklev) { n = 0; break; } - /*else FALLTHRU*/ - case BAG_OF_HOLDING: n = 1; break; - default: n = 0; break; - } - - for (n = rn2(n+1); n > 0; n--) { - if (box->otyp == ICE_BOX) { - if (!(otmp = mksobj(CORPSE, TRUE, TRUE))) continue; - /* Note: setting age to 0 is correct. Age has a different - * from usual meaning for objects stored in ice boxes. -KAA - */ - otmp->age = 0L; - if (otmp->timed) { - (void) stop_timer(ROT_CORPSE, obj_to_any(otmp)); - (void) stop_timer(REVIVE_MON, obj_to_any(otmp)); - } - } else { - register int tprob; - const struct icp *iprobs = boxiprobs; - - for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++) - ; - if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue; - - /* handle a couple of special cases */ - if (otmp->oclass == COIN_CLASS) { - /* 2.5 x level's usual amount; weight adjusted below */ - otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75)); - otmp->owt = weight(otmp); - } else while (otmp->otyp == ROCK) { - otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE); - if (otmp->quan > 2L) otmp->quan = 1L; - otmp->owt = weight(otmp); - } - if (box->otyp == BAG_OF_HOLDING) { - if (Is_mbag(otmp)) { - otmp->otyp = SACK; - otmp->spe = 0; - otmp->owt = weight(otmp); - } else while (otmp->otyp == WAN_CANCELLATION) - otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING); - } - } - (void) add_to_container(box, otmp); - } + register int n; + register struct obj *otmp; + + box->cobj = (struct obj *) 0; + + switch (box->otyp) { + case ICE_BOX: n = 20; break; + case CHEST: n = 5; break; + case LARGE_BOX: n = 3; break; + case SACK: + case OILSKIN_SACK: + /* initial inventory: sack starts out empty */ + if (moves <= 1 && !in_mklev) { n = 0; break; } + /*else FALLTHRU*/ + case BAG_OF_HOLDING: n = 1; break; + default: n = 0; break; + } + + for (n = rn2(n+1); n > 0; n--) { + if (box->otyp == ICE_BOX) { + if (!(otmp = mksobj(CORPSE, TRUE, TRUE))) continue; + /* Note: setting age to 0 is correct. Age has a different + * from usual meaning for objects stored in ice boxes. -KAA + */ + otmp->age = 0L; + if (otmp->timed) { + (void) stop_timer(ROT_CORPSE, obj_to_any(otmp)); + (void) stop_timer(REVIVE_MON, obj_to_any(otmp)); + } + } else { + register int tprob; + const struct icp *iprobs = boxiprobs; + + for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++) + ; + if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue; + + /* handle a couple of special cases */ + if (otmp->oclass == COIN_CLASS) { + /* 2.5 x level's usual amount; weight adjusted below */ + otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75)); + otmp->owt = weight(otmp); + } else while (otmp->otyp == ROCK) { + otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE); + if (otmp->quan > 2L) otmp->quan = 1L; + otmp->owt = weight(otmp); + } + if (box->otyp == BAG_OF_HOLDING) { + if (Is_mbag(otmp)) { + otmp->otyp = SACK; + otmp->spe = 0; + otmp->owt = weight(otmp); + } else while (otmp->otyp == WAN_CANCELLATION) + otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING); + } + } + (void) add_to_container(box, otmp); + } } int rndmonnum() /* select a random, common monster type */ { - register struct permonst *ptr; - register int i; - unsigned short excludeflags; + register struct permonst *ptr; + register int i; + unsigned short excludeflags; - /* Plan A: get a level-appropriate common monster */ - ptr = rndmonst(); - if (ptr) return(monsndx(ptr)); + /* Plan A: get a level-appropriate common monster */ + ptr = rndmonst(); + if (ptr) return(monsndx(ptr)); - /* Plan B: get any common monster */ - excludeflags = G_UNIQ | G_NOGEN | (Inhell ? G_NOHELL : G_HELL); - do { - i = rn1(SPECIAL_PM - LOW_PM, LOW_PM); - ptr = &mons[i]; - } while ((ptr->geno & excludeflags) != 0); + /* Plan B: get any common monster */ + excludeflags = G_UNIQ | G_NOGEN | (Inhell ? G_NOHELL : G_HELL); + do { + i = rn1(SPECIAL_PM - LOW_PM, LOW_PM); + ptr = &mons[i]; + } while ((ptr->geno & excludeflags) != 0); - return(i); + return(i); } void copy_oextra(obj2, obj1) struct obj *obj2, *obj1; { - if(!obj2 || !obj1 || !obj1->oextra) return; - - if (!obj2->oextra) obj2->oextra = newoextra(); - if (has_oname(obj1)) oname(obj2, ONAME(obj1)); - if (has_omonst(obj1)) { - if (!OMONST(obj2)) newomonst(obj2); - (void)memcpy((genericptr_t)OMONST(obj2), - (genericptr_t)OMONST(obj1), - sizeof(struct monst)); - OMONST(obj2)->mextra = (struct mextra *)0; - OMONST(obj2)->nmon = (struct monst *)0; + if(!obj2 || !obj1 || !obj1->oextra) return; + + if (!obj2->oextra) obj2->oextra = newoextra(); + if (has_oname(obj1)) oname(obj2, ONAME(obj1)); + if (has_omonst(obj1)) { + if (!OMONST(obj2)) newomonst(obj2); + (void)memcpy((genericptr_t)OMONST(obj2), + (genericptr_t)OMONST(obj1), + sizeof(struct monst)); + OMONST(obj2)->mextra = (struct mextra *)0; + OMONST(obj2)->nmon = (struct monst *)0; #if 0 - OMONST(obj2)->m_id = context.ident++; - if (OMONST(obj2)->m_id) /* ident overflowed */ - OMONST(obj2)->m_id = context.ident++; + OMONST(obj2)->m_id = context.ident++; + if (OMONST(obj2)->m_id) /* ident overflowed */ + OMONST(obj2)->m_id = context.ident++; #endif - if (OMONST(obj1)->mextra) - copy_mextra(OMONST(obj2),OMONST(obj1)); - } - if (has_omid(obj1)) { - if (!OMID(obj2)) newomid(obj2); - (void)memcpy((genericptr_t)OMID(obj2), - (genericptr_t)OMID(obj1), - sizeof(unsigned)); - } - if (has_olong(obj1)) { - if (!OLONG(obj2)) newolong(obj2); - (void)memcpy((genericptr_t)OLONG(obj2), - (genericptr_t)OLONG(obj1), - sizeof(long)); - } - if (has_omailcmd(obj1)) { - new_omailcmd(obj2, OMAILCMD(obj1)); - } + if (OMONST(obj1)->mextra) + copy_mextra(OMONST(obj2),OMONST(obj1)); + } + if (has_omid(obj1)) { + if (!OMID(obj2)) newomid(obj2); + (void)memcpy((genericptr_t)OMID(obj2), + (genericptr_t)OMID(obj1), + sizeof(unsigned)); + } + if (has_olong(obj1)) { + if (!OLONG(obj2)) newolong(obj2); + (void)memcpy((genericptr_t)OLONG(obj2), + (genericptr_t)OLONG(obj1), + sizeof(long)); + } + if (has_omailcmd(obj1)) { + new_omailcmd(obj2, OMAILCMD(obj1)); + } } /* @@ -372,33 +372,33 @@ splitobj(obj, num) struct obj *obj; long num; { - struct obj *otmp; - - if (obj->cobj || num <= 0L || obj->quan <= num) - panic("splitobj"); /* can't split containers */ - otmp = newobj(); - *otmp = *obj; /* copies whole structure */ - otmp->oextra = (struct oextra *)0; - otmp->o_id = context.ident++; - if (!otmp->o_id) otmp->o_id = context.ident++; /* ident overflowed */ - otmp->timed = 0; /* not timed, yet */ - otmp->lamplit = 0; /* ditto */ - otmp->owornmask = 0L; /* new object isn't worn */ - obj->quan -= num; - obj->owt = weight(obj); - otmp->quan = num; - otmp->owt = weight(otmp); /* -= obj->owt ? */ - obj->nobj = otmp; - /* Only set nexthere when on the floor, nexthere is also used */ - /* as a back pointer to the container object when contained. */ - if (obj->where == OBJ_FLOOR) - obj->nexthere = otmp; - copy_oextra(otmp, obj); - if (has_omid(otmp)) free_omid(otmp); /* only one association with m_id*/ - if (obj->unpaid) splitbill(obj,otmp); - if (obj->timed) obj_split_timers(obj, otmp); - if (obj_sheds_light(obj)) obj_split_light_source(obj, otmp); - return otmp; + struct obj *otmp; + + if (obj->cobj || num <= 0L || obj->quan <= num) + panic("splitobj"); /* can't split containers */ + otmp = newobj(); + *otmp = *obj; /* copies whole structure */ + otmp->oextra = (struct oextra *)0; + otmp->o_id = context.ident++; + if (!otmp->o_id) otmp->o_id = context.ident++; /* ident overflowed */ + otmp->timed = 0; /* not timed, yet */ + otmp->lamplit = 0; /* ditto */ + otmp->owornmask = 0L; /* new object isn't worn */ + obj->quan -= num; + obj->owt = weight(obj); + otmp->quan = num; + otmp->owt = weight(otmp); /* -= obj->owt ? */ + obj->nobj = otmp; + /* Only set nexthere when on the floor, nexthere is also used */ + /* as a back pointer to the container object when contained. */ + if (obj->where == OBJ_FLOOR) + obj->nexthere = otmp; + copy_oextra(otmp, obj); + if (has_omid(otmp)) free_omid(otmp); /* only one association with m_id*/ + if (obj->unpaid) splitbill(obj,otmp); + if (obj->timed) obj_split_timers(obj, otmp); + if (obj_sheds_light(obj)) obj_split_light_source(obj, otmp); + return otmp; } /* @@ -418,38 +418,38 @@ struct obj *otmp; otmp->where = obj->where; switch (obj->where) { case OBJ_FREE: - /* do nothing */ - break; + /* do nothing */ + break; case OBJ_INVENT: - otmp->nobj = obj->nobj; - obj->nobj = otmp; - extract_nobj(obj, &invent); - break; + otmp->nobj = obj->nobj; + obj->nobj = otmp; + extract_nobj(obj, &invent); + break; case OBJ_CONTAINED: - otmp->nobj = obj->nobj; - otmp->ocontainer = obj->ocontainer; - obj->nobj = otmp; - extract_nobj(obj, &obj->ocontainer->cobj); - break; + otmp->nobj = obj->nobj; + otmp->ocontainer = obj->ocontainer; + obj->nobj = otmp; + extract_nobj(obj, &obj->ocontainer->cobj); + break; case OBJ_MINVENT: - otmp->nobj = obj->nobj; - otmp->ocarry = obj->ocarry; - obj->nobj = otmp; - extract_nobj(obj, &obj->ocarry->minvent); - break; + otmp->nobj = obj->nobj; + otmp->ocarry = obj->ocarry; + obj->nobj = otmp; + extract_nobj(obj, &obj->ocarry->minvent); + break; case OBJ_FLOOR: - otmp->nobj = obj->nobj; - otmp->nexthere = obj->nexthere; - otmp->ox = obj->ox; - otmp->oy = obj->oy; - obj->nobj = otmp; - obj->nexthere = otmp; - extract_nobj(obj, &fobj); - extract_nexthere(obj, &level.objects[obj->ox][obj->oy]); - break; + otmp->nobj = obj->nobj; + otmp->nexthere = obj->nexthere; + otmp->ox = obj->ox; + otmp->oy = obj->oy; + obj->nobj = otmp; + obj->nexthere = otmp; + extract_nobj(obj, &fobj); + extract_nexthere(obj, &level.objects[obj->ox][obj->oy]); + break; default: - panic("replace_object: obj position"); - break; + panic("replace_object: obj position"); + break; } } @@ -471,38 +471,38 @@ void bill_dummy_object(otmp) register struct obj *otmp; { - register struct obj *dummy; - long cost = 0L; - - if (otmp->unpaid) { - cost = unpaid_cost(otmp, FALSE); - subfrombill(otmp, shop_keeper(*u.ushops)); - } - dummy = newobj(); - *dummy = *otmp; - dummy->oextra = (struct oextra *)0; - dummy->where = OBJ_FREE; - dummy->o_id = context.ident++; - if (!dummy->o_id) dummy->o_id = context.ident++; /* ident overflowed */ - dummy->timed = 0; - copy_oextra(dummy, otmp); - if (has_omid(dummy)) free_omid(dummy); /* only one association with m_id*/ - if (Is_candle(dummy)) dummy->lamplit = 0; - addtobill(dummy, FALSE, TRUE, TRUE); - if (cost) alter_cost(dummy, -cost); - /* no_charge is only valid for some locations */ - otmp->no_charge = (otmp->where == OBJ_FLOOR || - otmp->where == OBJ_CONTAINED) ? 1 : 0; - otmp->unpaid = 0; - return; + register struct obj *dummy; + long cost = 0L; + + if (otmp->unpaid) { + cost = unpaid_cost(otmp, FALSE); + subfrombill(otmp, shop_keeper(*u.ushops)); + } + dummy = newobj(); + *dummy = *otmp; + dummy->oextra = (struct oextra *)0; + dummy->where = OBJ_FREE; + dummy->o_id = context.ident++; + if (!dummy->o_id) dummy->o_id = context.ident++; /* ident overflowed */ + dummy->timed = 0; + copy_oextra(dummy, otmp); + if (has_omid(dummy)) free_omid(dummy); /* only one association with m_id*/ + if (Is_candle(dummy)) dummy->lamplit = 0; + addtobill(dummy, FALSE, TRUE, TRUE); + if (cost) alter_cost(dummy, -cost); + /* no_charge is only valid for some locations */ + otmp->no_charge = (otmp->where == OBJ_FLOOR || + otmp->where == OBJ_CONTAINED) ? 1 : 0; + otmp->unpaid = 0; + return; } /* alteration types; must match COST_xxx macros in hack.h */ static const char * const alteration_verbs[] = { - "cancel", "drain", "uncharge", "unbless", "uncurse", - "disenchant", "degrade", "dilute", "erase", "burn", - "neutralize", "destroy", "splatter", "bite", "open", - "break the lock on", "rust", "rot", "tarnish" + "cancel", "drain", "uncharge", "unbless", "uncurse", + "disenchant", "degrade", "dilute", "erase", "burn", + "neutralize", "destroy", "splatter", "bite", "open", + "break the lock on", "rust", "rot", "tarnish" }; /* possibly bill for an object which the player has just modified */ @@ -518,34 +518,34 @@ int alter_type; struct monst *shkp = 0; if (alter_type < 0 || alter_type >= SIZE(alteration_verbs)) { - impossible("invalid alteration type (%d)", alter_type); - alter_type = 0; + impossible("invalid alteration type (%d)", alter_type); + alter_type = 0; } ox = oy = 0; /* lint suppression */ objroom = '\0'; /* ditto */ if (carried(obj) || obj->where == OBJ_FREE) { - /* OBJ_FREE catches obj_no_longer_held()'s transformation - of crysknife back into worm tooth; the object has been - removed from inventory but not necessarily placed at - its new location yet--the unpaid flag will still be set - if this item is owned by a shop */ - if (!obj->unpaid) return; + /* OBJ_FREE catches obj_no_longer_held()'s transformation + of crysknife back into worm tooth; the object has been + removed from inventory but not necessarily placed at + its new location yet--the unpaid flag will still be set + if this item is owned by a shop */ + if (!obj->unpaid) return; } else { - /* this get_obj_location shouldn't fail, but if it does, - use hero's location */ - if (!get_obj_location(obj, &ox, &oy, CONTAINED_TOO)) - ox = u.ux, oy = u.uy; - if (!costly_spot(ox, oy)) return; - objroom = *in_rooms(ox, oy, SHOPBASE); - /* if no shop cares about it, we're done */ - if (!billable(&shkp, obj, objroom, FALSE)) return; + /* this get_obj_location shouldn't fail, but if it does, + use hero's location */ + if (!get_obj_location(obj, &ox, &oy, CONTAINED_TOO)) + ox = u.ux, oy = u.uy; + if (!costly_spot(ox, oy)) return; + objroom = *in_rooms(ox, oy, SHOPBASE); + /* if no shop cares about it, we're done */ + if (!billable(&shkp, obj, objroom, FALSE)) return; } if (obj->quan == 1L) - those = "that", them = "it"; + those = "that", them = "it"; else - those = "those", them = "them"; + those = "those", them = "them"; /* when shopkeeper describes the object as being uncursed or unblessed hero will know that it is now uncursed; will also make the feedback @@ -555,28 +555,28 @@ int alter_type; switch (obj->where) { case OBJ_FREE: /* obj_no_longer_held() */ case OBJ_INVENT: - if (set_bknown) obj->bknown = 1; - verbalize("You %s %s %s, you pay for %s!", - alteration_verbs[alter_type], those, - simpleonames(obj), them); - bill_dummy_object(obj); - break; + if (set_bknown) obj->bknown = 1; + verbalize("You %s %s %s, you pay for %s!", + alteration_verbs[alter_type], those, + simpleonames(obj), them); + bill_dummy_object(obj); + break; case OBJ_FLOOR: - if (set_bknown) obj->bknown = 1; - if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) { - verbalize("You %s %s, you pay for %s!", - alteration_verbs[alter_type], those, them); - bill_dummy_object(obj); - } else { - (void) stolen_value(obj, ox, oy, FALSE, FALSE); - } - break; + if (set_bknown) obj->bknown = 1; + if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) { + verbalize("You %s %s, you pay for %s!", + alteration_verbs[alter_type], those, them); + bill_dummy_object(obj); + } else { + (void) stolen_value(obj, ox, oy, FALSE, FALSE); + } + break; } } static const char dknowns[] = { - WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, - GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0 + WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, + GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0 }; struct obj * @@ -585,47 +585,47 @@ int otyp; boolean init; boolean artif; { - int mndx, tryct; - struct obj *otmp; - char let = objects[otyp].oc_class; - - otmp = newobj(); - *otmp = zeroobj; - otmp->age = monstermoves; - otmp->o_id = context.ident++; - if (!otmp->o_id) otmp->o_id = context.ident++; /* ident overflowed */ - otmp->quan = 1L; - otmp->oclass = let; - otmp->otyp = otyp; - otmp->where = OBJ_FREE; - otmp->dknown = index(dknowns, let) ? 0 : 1; - if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) || - otmp->otyp == SHIELD_OF_REFLECTION) - otmp->dknown = 0; - if (!objects[otmp->otyp].oc_uses_known) - otmp->known = 1; - otmp->lknown = 0; - otmp->cknown = 0; - otmp->corpsenm = NON_PM; - - if (init) switch (let) { - case WEAPON_CLASS: - otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L; - if(!rn2(11)) { - otmp->spe = rne(3); - otmp->blessed = rn2(2); - } else if(!rn2(10)) { - curse(otmp); - otmp->spe = -rne(3); - } else blessorcurse(otmp, 10); - if (is_poisonable(otmp) && !rn2(100)) - otmp->opoisoned = 1; - - if (artif && !rn2(20)) - otmp = mk_artifact(otmp, (aligntyp)A_NONE); - break; - case FOOD_CLASS: - otmp->oeaten = 0; + int mndx, tryct; + struct obj *otmp; + char let = objects[otyp].oc_class; + + otmp = newobj(); + *otmp = zeroobj; + otmp->age = monstermoves; + otmp->o_id = context.ident++; + if (!otmp->o_id) otmp->o_id = context.ident++; /* ident overflowed */ + otmp->quan = 1L; + otmp->oclass = let; + otmp->otyp = otyp; + otmp->where = OBJ_FREE; + otmp->dknown = index(dknowns, let) ? 0 : 1; + if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) || + otmp->otyp == SHIELD_OF_REFLECTION) + otmp->dknown = 0; + if (!objects[otmp->otyp].oc_uses_known) + otmp->known = 1; + otmp->lknown = 0; + otmp->cknown = 0; + otmp->corpsenm = NON_PM; + + if (init) switch (let) { + case WEAPON_CLASS: + otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L; + if(!rn2(11)) { + otmp->spe = rne(3); + otmp->blessed = rn2(2); + } else if(!rn2(10)) { + curse(otmp); + otmp->spe = -rne(3); + } else blessorcurse(otmp, 10); + if (is_poisonable(otmp) && !rn2(100)) + otmp->opoisoned = 1; + + if (artif && !rn2(20)) + otmp = mk_artifact(otmp, (aligntyp)A_NONE); + break; + case FOOD_CLASS: + otmp->oeaten = 0; switch(otmp->otyp) { case CORPSE: /* possibly overridden by mkcorpstat() */ @@ -673,204 +673,209 @@ boolean artif; otmp->quan = (long) rnd(2); break; } - if (Is_pudding(otmp)) { - otmp->oglobby = 1; - } else if (otmp->otyp != CORPSE && otmp->otyp != MEAT_RING + if (Is_pudding(otmp)) { + otmp->globby = 1; + otmp->known = otmp->bknown = otmp->rknown = otmp->dknown = 1; + /* this ensures that they don't fail merging because of + * BUC status or other irrelevancies */ + } else { + if (otmp->otyp != CORPSE && otmp->otyp != MEAT_RING && otmp->otyp != KELP_FROND && !rn2(6)) { - otmp->quan = 2L; + otmp->quan = 2L; + } + } + break; + case GEM_CLASS: + otmp->corpsenm = 0; /* LOADSTONE hack */ + if (otmp->otyp == LOADSTONE) curse(otmp); + else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6); + else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L; + else otmp->quan = 1L; + break; + case TOOL_CLASS: + switch(otmp->otyp) { + case TALLOW_CANDLE: + case WAX_CANDLE: otmp->spe = 1; + otmp->age = 20L * /* 400 or 200 */ + (long)objects[otmp->otyp].oc_cost; + otmp->lamplit = 0; + otmp->quan = 1L + + (long)(rn2(2) ? rn2(7) : 0); + blessorcurse(otmp, 5); + break; + case BRASS_LANTERN: + case OIL_LAMP: otmp->spe = 1; + otmp->age = (long) rn1(500,1000); + otmp->lamplit = 0; + blessorcurse(otmp, 5); + break; + case MAGIC_LAMP: otmp->spe = 1; + otmp->lamplit = 0; + blessorcurse(otmp, 2); + break; + case CHEST: + case LARGE_BOX: otmp->olocked = !!(rn2(5)); + otmp->otrapped = !(rn2(10)); + case ICE_BOX: + case SACK: + case OILSKIN_SACK: + case BAG_OF_HOLDING: mkbox_cnts(otmp); + break; + case LEASH: otmp->leashmon = 0; + break; + case EXPENSIVE_CAMERA: + case TINNING_KIT: + case MAGIC_MARKER: otmp->spe = rn1(70,30); + break; + case CAN_OF_GREASE: otmp->spe = rnd(25); + blessorcurse(otmp, 10); + break; + case CRYSTAL_BALL: otmp->spe = rnd(5); + blessorcurse(otmp, 2); + break; + case HORN_OF_PLENTY: + case BAG_OF_TRICKS: otmp->spe = rnd(20); + break; + case FIGURINE: { int tryct2 = 0; + do + otmp->corpsenm = rndmonnum(); + while(is_human(&mons[otmp->corpsenm]) + && tryct2++ < 30); + blessorcurse(otmp, 4); + break; + } + case BELL_OF_OPENING: otmp->spe = 3; + break; + case MAGIC_FLUTE: + case MAGIC_HARP: + case FROST_HORN: + case FIRE_HORN: + case DRUM_OF_EARTHQUAKE: + otmp->spe = rn1(5,4); + break; } - break; - case GEM_CLASS: - otmp->corpsenm = 0; /* LOADSTONE hack */ - if (otmp->otyp == LOADSTONE) curse(otmp); - else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6); - else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L; - else otmp->quan = 1L; - break; - case TOOL_CLASS: - switch(otmp->otyp) { - case TALLOW_CANDLE: - case WAX_CANDLE: otmp->spe = 1; - otmp->age = 20L * /* 400 or 200 */ - (long)objects[otmp->otyp].oc_cost; - otmp->lamplit = 0; - otmp->quan = 1L + - (long)(rn2(2) ? rn2(7) : 0); - blessorcurse(otmp, 5); - break; - case BRASS_LANTERN: - case OIL_LAMP: otmp->spe = 1; - otmp->age = (long) rn1(500,1000); - otmp->lamplit = 0; - blessorcurse(otmp, 5); - break; - case MAGIC_LAMP: otmp->spe = 1; - otmp->lamplit = 0; - blessorcurse(otmp, 2); - break; - case CHEST: - case LARGE_BOX: otmp->olocked = !!(rn2(5)); - otmp->otrapped = !(rn2(10)); - case ICE_BOX: - case SACK: - case OILSKIN_SACK: - case BAG_OF_HOLDING: mkbox_cnts(otmp); - break; - case LEASH: otmp->leashmon = 0; - break; - case EXPENSIVE_CAMERA: - case TINNING_KIT: - case MAGIC_MARKER: otmp->spe = rn1(70,30); - break; - case CAN_OF_GREASE: otmp->spe = rnd(25); - blessorcurse(otmp, 10); - break; - case CRYSTAL_BALL: otmp->spe = rnd(5); - blessorcurse(otmp, 2); - break; - case HORN_OF_PLENTY: - case BAG_OF_TRICKS: otmp->spe = rnd(20); - break; - case FIGURINE: { int tryct2 = 0; - do - otmp->corpsenm = rndmonnum(); - while(is_human(&mons[otmp->corpsenm]) - && tryct2++ < 30); - blessorcurse(otmp, 4); - break; - } - case BELL_OF_OPENING: otmp->spe = 3; - break; - case MAGIC_FLUTE: - case MAGIC_HARP: - case FROST_HORN: - case FIRE_HORN: - case DRUM_OF_EARTHQUAKE: - otmp->spe = rn1(5,4); - break; - } - break; - case AMULET_CLASS: - if (otmp->otyp == AMULET_OF_YENDOR) context.made_amulet = TRUE; - if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION || - otmp->otyp == AMULET_OF_CHANGE || - otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) { - curse(otmp); - } else blessorcurse(otmp, 10); - case VENOM_CLASS: - case CHAIN_CLASS: - case BALL_CLASS: - break; - case POTION_CLASS: - otmp->fromsink = 0; - if (otmp->otyp == POT_OIL) - otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */ - /* fall through */ - case SCROLL_CLASS: + break; + case AMULET_CLASS: + if (otmp->otyp == AMULET_OF_YENDOR) context.made_amulet = TRUE; + if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION || + otmp->otyp == AMULET_OF_CHANGE || + otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) { + curse(otmp); + } else blessorcurse(otmp, 10); + case VENOM_CLASS: + case CHAIN_CLASS: + case BALL_CLASS: + break; + case POTION_CLASS: + otmp->fromsink = 0; + if (otmp->otyp == POT_OIL) + otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */ + /* fall through */ + case SCROLL_CLASS: #ifdef MAIL - if (otmp->otyp != SCR_MAIL) + if (otmp->otyp != SCR_MAIL) #endif - blessorcurse(otmp, 4); - break; - case SPBOOK_CLASS: - otmp->spestudied = 0; - blessorcurse(otmp, 17); - break; - case ARMOR_CLASS: - if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS || - otmp->otyp == LEVITATION_BOOTS || - otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT || - otmp->otyp == GAUNTLETS_OF_FUMBLING || - !rn2(11))) { - curse(otmp); - otmp->spe = -rne(3); - } else if(!rn2(10)) { - otmp->blessed = rn2(2); - otmp->spe = rne(3); - } else blessorcurse(otmp, 10); - if (artif && !rn2(40)) - otmp = mk_artifact(otmp, (aligntyp)A_NONE); - /* simulate lacquered armor for samurai */ - if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && - (moves <= 1 || In_quest(&u.uz))) { + blessorcurse(otmp, 4); + break; + case SPBOOK_CLASS: + otmp->spestudied = 0; + blessorcurse(otmp, 17); + break; + case ARMOR_CLASS: + if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS || + otmp->otyp == LEVITATION_BOOTS || + otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT || + otmp->otyp == GAUNTLETS_OF_FUMBLING || + !rn2(11))) { + curse(otmp); + otmp->spe = -rne(3); + } else if(!rn2(10)) { + otmp->blessed = rn2(2); + otmp->spe = rne(3); + } else blessorcurse(otmp, 10); + if (artif && !rn2(40)) + otmp = mk_artifact(otmp, (aligntyp)A_NONE); + /* simulate lacquered armor for samurai */ + if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && + (moves <= 1 || In_quest(&u.uz))) { #ifdef UNIXPC - /* optimizer bitfield bug */ - otmp->oerodeproof = 1; - otmp->rknown = 1; + /* optimizer bitfield bug */ + otmp->oerodeproof = 1; + otmp->rknown = 1; #else - otmp->oerodeproof = otmp->rknown = 1; + otmp->oerodeproof = otmp->rknown = 1; #endif - } - break; - case WAND_CLASS: - if(otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else - otmp->spe = rn1(5, - (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); - blessorcurse(otmp, 17); - otmp->recharged = 0; /* used to control recharging */ - break; - case RING_CLASS: - if(objects[otmp->otyp].oc_charged) { - blessorcurse(otmp, 3); - if(rn2(10)) { - if(rn2(10) && bcsign(otmp)) - otmp->spe = bcsign(otmp) * rne(3); - else otmp->spe = rn2(2) ? rne(3) : -rne(3); - } - /* make useless +0 rings much less common */ - if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3); - /* negative rings are usually cursed */ - if (otmp->spe < 0 && rn2(5)) curse(otmp); - } else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION || - otmp->otyp == RIN_POLYMORPH || - otmp->otyp == RIN_AGGRAVATE_MONSTER || - otmp->otyp == RIN_HUNGER || !rn2(9))) { - curse(otmp); - } - break; - case ROCK_CLASS: - switch (otmp->otyp) { - case STATUE: - /* possibly overridden by mkcorpstat() */ - otmp->corpsenm = rndmonnum(); - if (!verysmall(&mons[otmp->corpsenm]) && - rn2(level_difficulty()/2 + 10) > 10) - (void) add_to_container(otmp, - mkobj(SPBOOK_CLASS,FALSE)); - } - break; - case COIN_CLASS: - break; /* do nothing */ - default: - impossible("impossible mkobj %d, sym '%c'.", otmp->otyp, - objects[otmp->otyp].oc_class); - return (struct obj *)0; - } - - /* some things must get done (corpsenm, timers) even if init = 0 */ - switch (otmp->otyp) { - case CORPSE: - if (otmp->corpsenm == NON_PM) { - otmp->corpsenm = undead_to_corpse(rndmonnum()); - if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE|G_GONE)) - otmp->corpsenm = urole.malenum; - } - /*FALLTHRU*/ - case STATUE: - case FIGURINE: - if (otmp->corpsenm == NON_PM) otmp->corpsenm = rndmonnum(); - /*FALLTHRU*/ - case EGG: - /* case TIN: */ - set_corpsenm(otmp, otmp->corpsenm); - break; - } - - /* unique objects may have an associated artifact entry */ - if (objects[otyp].oc_unique && !otmp->oartifact) - otmp = mk_artifact(otmp, (aligntyp)A_NONE); - otmp->owt = weight(otmp); - return(otmp); + } + break; + case WAND_CLASS: + if(otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else + otmp->spe = rn1(5, + (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); + blessorcurse(otmp, 17); + otmp->recharged = 0; /* used to control recharging */ + break; + case RING_CLASS: + if(objects[otmp->otyp].oc_charged) { + blessorcurse(otmp, 3); + if(rn2(10)) { + if(rn2(10) && bcsign(otmp)) + otmp->spe = bcsign(otmp) * rne(3); + else otmp->spe = rn2(2) ? rne(3) : -rne(3); + } + /* make useless +0 rings much less common */ + if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3); + /* negative rings are usually cursed */ + if (otmp->spe < 0 && rn2(5)) curse(otmp); + } else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION || + otmp->otyp == RIN_POLYMORPH || + otmp->otyp == RIN_AGGRAVATE_MONSTER || + otmp->otyp == RIN_HUNGER || !rn2(9))) { + curse(otmp); + } + break; + case ROCK_CLASS: + switch (otmp->otyp) { + case STATUE: + /* possibly overridden by mkcorpstat() */ + otmp->corpsenm = rndmonnum(); + if (!verysmall(&mons[otmp->corpsenm]) && + rn2(level_difficulty()/2 + 10) > 10) + (void) add_to_container(otmp, + mkobj(SPBOOK_CLASS,FALSE)); + } + break; + case COIN_CLASS: + break; /* do nothing */ + default: + impossible("impossible mkobj %d, sym '%c'.", otmp->otyp, + objects[otmp->otyp].oc_class); + return (struct obj *)0; + } + + /* some things must get done (corpsenm, timers) even if init = 0 */ + switch (otmp->otyp) { + case CORPSE: + if (otmp->corpsenm == NON_PM) { + otmp->corpsenm = undead_to_corpse(rndmonnum()); + if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE|G_GONE)) + otmp->corpsenm = urole.malenum; + } + /*FALLTHRU*/ + case STATUE: + case FIGURINE: + if (otmp->corpsenm == NON_PM) otmp->corpsenm = rndmonnum(); + /*FALLTHRU*/ + case EGG: + /* case TIN: */ + set_corpsenm(otmp, otmp->corpsenm); + break; + } + + /* unique objects may have an associated artifact entry */ + if (objects[otyp].oc_unique && !otmp->oartifact) + otmp = mk_artifact(otmp, (aligntyp)A_NONE); + otmp->owt = weight(otmp); + return(otmp); } /* @@ -898,38 +903,38 @@ set_corpsenm(obj, id) struct obj *obj; int id; { - long when = 0L; - - if (obj->timed) { - if (obj->otyp == EGG) - when = stop_timer(HATCH_EGG, obj_to_any(obj)); - else { - when = 0L; - obj_stop_timers(obj); /* corpse or figurine */ - } - } - obj->corpsenm = id; - switch(obj->otyp) { - case CORPSE: - start_corpse_timeout(obj); - obj->owt = weight(obj); - break; - case FIGURINE: - if (obj->corpsenm != NON_PM - && !dead_species(obj->corpsenm,TRUE) - && (carried(obj) || mcarried(obj))) - attach_fig_transform_timeout(obj); - obj->owt = weight(obj); - break; - case EGG: - if (obj->corpsenm != NON_PM - && !dead_species(obj->corpsenm,TRUE)) - attach_egg_hatch_timeout(obj, when); - break; - default: /* tin, etc. */ - obj->owt = weight(obj); - break; - } + long when = 0L; + + if (obj->timed) { + if (obj->otyp == EGG) + when = stop_timer(HATCH_EGG, obj_to_any(obj)); + else { + when = 0L; + obj_stop_timers(obj); /* corpse or figurine */ + } + } + obj->corpsenm = id; + switch(obj->otyp) { + case CORPSE: + start_corpse_timeout(obj); + obj->owt = weight(obj); + break; + case FIGURINE: + if (obj->corpsenm != NON_PM + && !dead_species(obj->corpsenm,TRUE) + && (carried(obj) || mcarried(obj))) + attach_fig_transform_timeout(obj); + obj->owt = weight(obj); + break; + case EGG: + if (obj->corpsenm != NON_PM + && !dead_species(obj->corpsenm,TRUE)) + attach_egg_hatch_timeout(obj, when); + break; + default: /* tin, etc. */ + obj->owt = weight(obj); + break; + } } /* @@ -938,50 +943,50 @@ int id; */ void start_corpse_timeout(body) - struct obj *body; + struct obj *body; { - long when; /* rot away when this old */ - long corpse_age; /* age of corpse */ - int rot_adjust; - short action; + long when; /* rot away when this old */ + long corpse_age; /* age of corpse */ + int rot_adjust; + short action; #define TAINT_AGE (50L) /* age when corpses go bad */ #define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */ #define ROT_AGE (250L) /* age when corpses rot away */ - /* lizards and lichen don't rot or revive */ - if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return; - - action = ROT_CORPSE; /* default action: rot away */ - rot_adjust = in_mklev ? 25 : 10; /* give some variation */ - corpse_age = monstermoves - body->age; - if (corpse_age > ROT_AGE) - when = rot_adjust; - else - when = ROT_AGE - corpse_age; - when += (long)(rnz(rot_adjust) - rot_adjust); - - if (is_rider(&mons[body->corpsenm])) { - /* - * Riders always revive. They have a 1/3 chance per turn - * of reviving after 12 turns. Always revive by 500. - */ - action = REVIVE_MON; - for (when = 12L; when < 500L; when++) - if (!rn2(3)) break; - - } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) { - long age; - for (age = 2; age <= TAINT_AGE; age++) - if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */ - action = REVIVE_MON; - when = age; - break; - } - } - - if (body->norevive) body->norevive = 0; - (void) start_timer(when, TIMER_OBJECT, action, obj_to_any(body)); + /* lizards and lichen don't rot or revive */ + if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return; + + action = ROT_CORPSE; /* default action: rot away */ + rot_adjust = in_mklev ? 25 : 10; /* give some variation */ + corpse_age = monstermoves - body->age; + if (corpse_age > ROT_AGE) + when = rot_adjust; + else + when = ROT_AGE - corpse_age; + when += (long)(rnz(rot_adjust) - rot_adjust); + + if (is_rider(&mons[body->corpsenm])) { + /* + * Riders always revive. They have a 1/3 chance per turn + * of reviving after 12 turns. Always revive by 500. + */ + action = REVIVE_MON; + for (when = 12L; when < 500L; when++) + if (!rn2(3)) break; + + } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) { + long age; + for (age = 2; age <= TAINT_AGE; age++) + if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */ + action = REVIVE_MON; + when = age; + break; + } + } + + if (body->norevive) body->norevive = 0; + (void) start_timer(when, TIMER_OBJECT, action, obj_to_any(body)); } STATIC_OVL void @@ -989,38 +994,38 @@ maybe_adjust_light(obj, old_range) struct obj *obj; int old_range; { - char buf[BUFSZ]; - xchar ox, oy; - int new_range = arti_light_radius(obj), - delta = new_range - old_range; - - /* radius of light emitting artifact varies by curse/bless state - so will change after blessing or cursing */ - if (delta) { - obj_adjust_light_radius(obj, new_range); - /* simplifying assumptions: hero is wielding this object; - artifacts have to be in use to emit light and monsters' - gear won't change bless or curse state */ - if (!Blind && get_obj_location(obj, &ox, &oy, 0)) { - *buf = '\0'; - if (iflags.last_msg == PLNMSG_OBJ_GLOWS) - /* we just saw "The glows ." from dipping */ - Strcpy(buf, (obj->quan == 1L) ? "It" : "They"); - else if (carried(obj) || cansee(ox, oy)) - Strcpy(buf, Yname2(obj)); - if (*buf) { - /* initial activation says "dimly" if cursed, - "brightly" if uncursed, and "brilliantly" if blessed; - when changing intensity, using "less brightly" is - straightforward for dimming, but we need "brighter" - rather than "more brightly" for brightening; ugh */ - pline("%s %s %s%s.", - buf, otense(obj, "shine"), - (abs(delta) > 1) ? "much " : "", - (delta > 0) ? "brighter" : "less brightly"); - } - } - } + char buf[BUFSZ]; + xchar ox, oy; + int new_range = arti_light_radius(obj), + delta = new_range - old_range; + + /* radius of light emitting artifact varies by curse/bless state + so will change after blessing or cursing */ + if (delta) { + obj_adjust_light_radius(obj, new_range); + /* simplifying assumptions: hero is wielding this object; + artifacts have to be in use to emit light and monsters' + gear won't change bless or curse state */ + if (!Blind && get_obj_location(obj, &ox, &oy, 0)) { + *buf = '\0'; + if (iflags.last_msg == PLNMSG_OBJ_GLOWS) + /* we just saw "The glows ." from dipping */ + Strcpy(buf, (obj->quan == 1L) ? "It" : "They"); + else if (carried(obj) || cansee(ox, oy)) + Strcpy(buf, Yname2(obj)); + if (*buf) { + /* initial activation says "dimly" if cursed, + "brightly" if uncursed, and "brilliantly" if blessed; + when changing intensity, using "less brightly" is + straightforward for dimming, but we need "brighter" + rather than "more brightly" for brightening; ugh */ + pline("%s %s %s%s.", + buf, otense(obj, "shine"), + (abs(delta) > 1) ? "much " : "", + (delta > 0) ? "brighter" : "less brightly"); + } + } + } } /* @@ -1033,84 +1038,84 @@ void bless(otmp) register struct obj *otmp; { - int old_light = 0; + int old_light = 0; - if (otmp->oclass == COIN_CLASS) return; - if (otmp->lamplit) old_light = arti_light_radius(otmp); - otmp->cursed = 0; - otmp->blessed = 1; - if (carried(otmp) && confers_luck(otmp)) - set_moreluck(); - else if (otmp->otyp == BAG_OF_HOLDING) - otmp->owt = weight(otmp); - else if (otmp->otyp == FIGURINE && otmp->timed) - (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp)); - if (otmp->lamplit) maybe_adjust_light(otmp, old_light); - return; + if (otmp->oclass == COIN_CLASS) return; + if (otmp->lamplit) old_light = arti_light_radius(otmp); + otmp->cursed = 0; + otmp->blessed = 1; + if (carried(otmp) && confers_luck(otmp)) + set_moreluck(); + else if (otmp->otyp == BAG_OF_HOLDING) + otmp->owt = weight(otmp); + else if (otmp->otyp == FIGURINE && otmp->timed) + (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp)); + if (otmp->lamplit) maybe_adjust_light(otmp, old_light); + return; } void unbless(otmp) register struct obj *otmp; { - int old_light = 0; + int old_light = 0; - if (otmp->lamplit) old_light = arti_light_radius(otmp); - otmp->blessed = 0; - if (carried(otmp) && confers_luck(otmp)) - set_moreluck(); - else if (otmp->otyp == BAG_OF_HOLDING) - otmp->owt = weight(otmp); - if (otmp->lamplit) maybe_adjust_light(otmp, old_light); + if (otmp->lamplit) old_light = arti_light_radius(otmp); + otmp->blessed = 0; + if (carried(otmp) && confers_luck(otmp)) + set_moreluck(); + else if (otmp->otyp == BAG_OF_HOLDING) + otmp->owt = weight(otmp); + if (otmp->lamplit) maybe_adjust_light(otmp, old_light); } void curse(otmp) register struct obj *otmp; { - int old_light = 0; - - if (otmp->oclass == COIN_CLASS) return; - if (otmp->lamplit) old_light = arti_light_radius(otmp); - otmp->blessed = 0; - otmp->cursed = 1; - /* welded two-handed weapon interferes with some armor removal */ - if (otmp == uwep && bimanual(uwep)) reset_remarm(); - /* rules at top of wield.c state that twoweapon cannot be done - with cursed alternate weapon */ - if (otmp == uswapwep && u.twoweap) - drop_uswapwep(); - /* some cursed items need immediate updating */ - if (carried(otmp) && confers_luck(otmp)) - set_moreluck(); - else if (otmp->otyp == BAG_OF_HOLDING) - otmp->owt = weight(otmp); - else if (otmp->otyp == FIGURINE) { - if (otmp->corpsenm != NON_PM - && !dead_species(otmp->corpsenm,TRUE) - && (carried(otmp) || mcarried(otmp))) - attach_fig_transform_timeout(otmp); - } - if (otmp->lamplit) maybe_adjust_light(otmp, old_light); - return; + int old_light = 0; + + if (otmp->oclass == COIN_CLASS) return; + if (otmp->lamplit) old_light = arti_light_radius(otmp); + otmp->blessed = 0; + otmp->cursed = 1; + /* welded two-handed weapon interferes with some armor removal */ + if (otmp == uwep && bimanual(uwep)) reset_remarm(); + /* rules at top of wield.c state that twoweapon cannot be done + with cursed alternate weapon */ + if (otmp == uswapwep && u.twoweap) + drop_uswapwep(); + /* some cursed items need immediate updating */ + if (carried(otmp) && confers_luck(otmp)) + set_moreluck(); + else if (otmp->otyp == BAG_OF_HOLDING) + otmp->owt = weight(otmp); + else if (otmp->otyp == FIGURINE) { + if (otmp->corpsenm != NON_PM + && !dead_species(otmp->corpsenm,TRUE) + && (carried(otmp) || mcarried(otmp))) + attach_fig_transform_timeout(otmp); + } + if (otmp->lamplit) maybe_adjust_light(otmp, old_light); + return; } void uncurse(otmp) register struct obj *otmp; { - int old_light = 0; + int old_light = 0; - if (otmp->lamplit) old_light = arti_light_radius(otmp); - otmp->cursed = 0; - if (carried(otmp) && confers_luck(otmp)) - set_moreluck(); - else if (otmp->otyp == BAG_OF_HOLDING) - otmp->owt = weight(otmp); - else if (otmp->otyp == FIGURINE && otmp->timed) - (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp)); - if (otmp->lamplit) maybe_adjust_light(otmp, old_light); - return; + if (otmp->lamplit) old_light = arti_light_radius(otmp); + otmp->cursed = 0; + if (carried(otmp) && confers_luck(otmp)) + set_moreluck(); + else if (otmp->otyp == BAG_OF_HOLDING) + otmp->owt = weight(otmp); + else if (otmp->otyp == FIGURINE && otmp->timed) + (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp)); + if (otmp->lamplit) maybe_adjust_light(otmp, old_light); + return; } void @@ -1118,23 +1123,23 @@ blessorcurse(otmp, chance) register struct obj *otmp; register int chance; { - if(otmp->blessed || otmp->cursed) return; + if(otmp->blessed || otmp->cursed) return; - if(!rn2(chance)) { - if(!rn2(2)) { - curse(otmp); - } else { - bless(otmp); - } - } - return; + if(!rn2(chance)) { + if(!rn2(2)) { + curse(otmp); + } else { + bless(otmp); + } + } + return; } int bcsign(otmp) register struct obj *otmp; { - return(!!otmp->blessed - !!otmp->cursed); + return(!!otmp->blessed - !!otmp->cursed); } /* @@ -1149,54 +1154,54 @@ int weight(obj) register struct obj *obj; { - int wt = objects[obj->otyp].oc_weight; - - if (SchroedingersBox(obj)) - wt += mons[PM_HOUSECAT].cwt; - if (Is_container(obj) || obj->otyp == STATUE) { - struct obj *contents; - register int cwt = 0; - - if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM) - wt = (int)obj->quan * - ((int)mons[obj->corpsenm].cwt * 3 / 2); - - for(contents=obj->cobj; contents; contents=contents->nobj) - cwt += weight(contents); - /* - * The weight of bags of holding is calculated as the weight - * of the bag plus the weight of the bag's contents modified - * as follows: - * - * Bag status Weight of contents - * ---------- ------------------ - * cursed 2x - * blessed x/4 [rounded up: (x+3)/4] - * otherwise x/2 [rounded up: (x+1)/2] - * - * The macro DELTA_CWT in pickup.c also implements these - * weight equations. - */ - if (obj->otyp == BAG_OF_HOLDING) - cwt = obj->cursed ? (cwt * 2) : - obj->blessed ? ((cwt + 3) / 4) : - ((cwt + 1) / 2); - - return wt + cwt; - } - if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM) { - long long_wt = obj->quan * (long) mons[obj->corpsenm].cwt; - - wt = (long_wt > LARGEST_INT) ? LARGEST_INT : (int)long_wt; - if (obj->oeaten) wt = eaten_stat(wt, obj); - return wt; - } else if (obj->oclass == FOOD_CLASS && obj->oeaten) { - return eaten_stat((int)obj->quan * wt, obj); - } else if (obj->oclass == COIN_CLASS) - return (int)((obj->quan + 50L) / 100L); - else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0) - return((int)(obj->owt)); /* kludge for "very" heavy iron ball */ - return(wt ? wt*(int)obj->quan : ((int)obj->quan + 1)>>1); + int wt = objects[obj->otyp].oc_weight; + + if (SchroedingersBox(obj)) + wt += mons[PM_HOUSECAT].cwt; + if (Is_container(obj) || obj->otyp == STATUE) { + struct obj *contents; + register int cwt = 0; + + if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM) + wt = (int)obj->quan * + ((int)mons[obj->corpsenm].cwt * 3 / 2); + + for(contents=obj->cobj; contents; contents=contents->nobj) + cwt += weight(contents); + /* + * The weight of bags of holding is calculated as the weight + * of the bag plus the weight of the bag's contents modified + * as follows: + * + * Bag status Weight of contents + * ---------- ------------------ + * cursed 2x + * blessed x/4 [rounded up: (x+3)/4] + * otherwise x/2 [rounded up: (x+1)/2] + * + * The macro DELTA_CWT in pickup.c also implements these + * weight equations. + */ + if (obj->otyp == BAG_OF_HOLDING) + cwt = obj->cursed ? (cwt * 2) : + obj->blessed ? ((cwt + 3) / 4) : + ((cwt + 1) / 2); + + return wt + cwt; + } + if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM) { + long long_wt = obj->quan * (long) mons[obj->corpsenm].cwt; + + wt = (long_wt > LARGEST_INT) ? LARGEST_INT : (int)long_wt; + if (obj->oeaten) wt = eaten_stat(wt, obj); + return wt; + } else if (obj->oclass == FOOD_CLASS && obj->oeaten) { + return eaten_stat((int)obj->quan * wt, obj); + } else if (obj->oclass == COIN_CLASS) + return (int)((obj->quan + 50L) / 100L); + else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0) + return((int)(obj->owt)); /* kludge for "very" heavy iron ball */ + return(wt ? wt*(int)obj->quan : ((int)obj->quan + 1)>>1); } static int treefruits[] = {APPLE,ORANGE,PEAR,BANANA,EUCALYPTUS_LEAF}; @@ -1205,7 +1210,7 @@ struct obj * rnd_treefruit_at(x,y) int x, y; { - return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE); + return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE); } struct obj * @@ -1216,12 +1221,12 @@ int x, y; register struct obj *gold = g_at(x,y); if (amount <= 0L) - amount = (long)(1 + rnd(level_difficulty()+2) * rnd(30)); + amount = (long)(1 + rnd(level_difficulty()+2) * rnd(30)); if (gold) { - gold->quan += amount; + gold->quan += amount; } else { - gold = mksobj_at(GOLD_PIECE, x, y, TRUE, FALSE); - gold->quan = amount; + gold = mksobj_at(GOLD_PIECE, x, y, TRUE, FALSE); + gold->quan = amount; } gold->owt = weight(gold); return (gold); @@ -1229,9 +1234,9 @@ int x, y; /* return TRUE if the corpse has special timing */ #define special_corpse(num) (((num) == PM_LIZARD) \ - || ((num) == PM_LICHEN) \ - || (is_rider(&mons[num])) \ - || (mons[num].mlet == S_TROLL)) + || ((num) == PM_LICHEN) \ + || (is_rider(&mons[num])) \ + || (mons[num].mlet == S_TROLL)) /* * OEXTRA note: Passing mtmp causes mtraits to be saved @@ -1250,41 +1255,41 @@ struct permonst *ptr; int x, y; unsigned corpstatflags; { - register struct obj *otmp; - boolean init = ((corpstatflags & CORPSTAT_INIT) != 0); - - if (objtype != CORPSE && objtype != STATUE) - impossible("making corpstat type %d", objtype); - if (x == 0 && y == 0) { /* special case - random placement */ - otmp = mksobj(objtype, init, FALSE); - if (otmp) (void)rloco(otmp); - } else - otmp = mksobj_at(objtype, x, y, init, FALSE); - if (otmp) { - if (mtmp) { - struct obj *otmp2; - - if (!ptr) ptr = mtmp->data; - /* save_mtraits frees original data pointed to by otmp */ - otmp2 = save_mtraits(otmp, mtmp); - if (otmp2) otmp = otmp2; - } - /* use the corpse or statue produced by mksobj() as-is - unless `ptr' is non-null */ - if (ptr) { - int old_corpsenm = otmp->corpsenm; - - otmp->corpsenm = monsndx(ptr); - otmp->owt = weight(otmp); - if (otmp->otyp == CORPSE && - (special_corpse(old_corpsenm) || - special_corpse(otmp->corpsenm))) { - obj_stop_timers(otmp); - start_corpse_timeout(otmp); - } - } - } - return(otmp); + register struct obj *otmp; + boolean init = ((corpstatflags & CORPSTAT_INIT) != 0); + + if (objtype != CORPSE && objtype != STATUE) + impossible("making corpstat type %d", objtype); + if (x == 0 && y == 0) { /* special case - random placement */ + otmp = mksobj(objtype, init, FALSE); + if (otmp) (void)rloco(otmp); + } else + otmp = mksobj_at(objtype, x, y, init, FALSE); + if (otmp) { + if (mtmp) { + struct obj *otmp2; + + if (!ptr) ptr = mtmp->data; + /* save_mtraits frees original data pointed to by otmp */ + otmp2 = save_mtraits(otmp, mtmp); + if (otmp2) otmp = otmp2; + } + /* use the corpse or statue produced by mksobj() as-is + unless `ptr' is non-null */ + if (ptr) { + int old_corpsenm = otmp->corpsenm; + + otmp->corpsenm = monsndx(ptr); + otmp->owt = weight(otmp); + if (otmp->otyp == CORPSE && + (special_corpse(old_corpsenm) || + special_corpse(otmp->corpsenm))) { + obj_stop_timers(otmp); + start_corpse_timeout(otmp); + } + } + } + return(otmp); } /* @@ -1299,16 +1304,16 @@ int corpse_revive_type(obj) struct obj *obj; { - int revivetype; - struct monst *mtmp; - if (has_omonst(obj) && - ((mtmp = get_mtraits(obj, FALSE)) != (struct monst *)0)) { - /* mtmp is a temporary pointer to a monster's stored - attributes, not a real monster */ - revivetype = mtmp->mnum; - } else - revivetype = obj->corpsenm; - return revivetype; + int revivetype; + struct monst *mtmp; + if (has_omonst(obj) && + ((mtmp = get_mtraits(obj, FALSE)) != (struct monst *)0)) { + /* mtmp is a temporary pointer to a monster's stored + attributes, not a real monster */ + revivetype = mtmp->mnum; + } else + revivetype = obj->corpsenm; + return revivetype; } /* @@ -1331,22 +1336,22 @@ save_mtraits(obj, mtmp) struct obj *obj; struct monst *mtmp; { - if (mtmp->ispriest) forget_temple_entry(mtmp); /* EPRI() */ - if (!has_omonst(obj)) newomonst(obj); - if (has_omonst(obj)) { - struct monst *mtmp2 = OMONST(obj); - *mtmp2 = *mtmp; - mtmp2->mextra = (struct mextra *)0; - if (mtmp->data) mtmp2->mnum = monsndx(mtmp->data); - /* invalidate pointers */ - /* m_id is needed to know if this is a revived quest leader */ - /* but m_id must be cleared when loading bones */ - mtmp2->nmon = (struct monst *)0; - mtmp2->data = (struct permonst *)0; - mtmp2->minvent = (struct obj *)0; - if (mtmp->mextra) copy_mextra(mtmp2, mtmp); - } - return obj; + if (mtmp->ispriest) forget_temple_entry(mtmp); /* EPRI() */ + if (!has_omonst(obj)) newomonst(obj); + if (has_omonst(obj)) { + struct monst *mtmp2 = OMONST(obj); + *mtmp2 = *mtmp; + mtmp2->mextra = (struct mextra *)0; + if (mtmp->data) mtmp2->mnum = monsndx(mtmp->data); + /* invalidate pointers */ + /* m_id is needed to know if this is a revived quest leader */ + /* but m_id must be cleared when loading bones */ + mtmp2->nmon = (struct monst *)0; + mtmp2->data = (struct permonst *)0; + mtmp2->minvent = (struct obj *)0; + if (mtmp->mextra) copy_mextra(mtmp2, mtmp); + } + return obj; } /* returns a pointer to a new monst structure based on @@ -1357,22 +1362,22 @@ get_mtraits(obj, copyof) struct obj *obj; boolean copyof; { - struct monst *mtmp = (struct monst *)0; - struct monst *mnew = (struct monst *)0; - - if (has_omonst(obj)) mtmp = OMONST(obj); - if (mtmp) { - if (copyof) { - mnew = newmonst(); - *mnew = *mtmp; - mnew->mextra = (struct mextra *)0; - if (mtmp->mextra) copy_mextra(mnew, mtmp); - } else { - /* Never insert this returned pointer into mon chains! */ - mnew = mtmp; - } - } - return mnew; + struct monst *mtmp = (struct monst *)0; + struct monst *mnew = (struct monst *)0; + + if (has_omonst(obj)) mtmp = OMONST(obj); + if (mtmp) { + if (copyof) { + mnew = newmonst(); + *mnew = *mtmp; + mnew->mextra = (struct mextra *)0; + if (mtmp->mextra) copy_mextra(mnew, mtmp); + } else { + /* Never insert this returned pointer into mon chains! */ + mnew = mtmp; + } + } + return mnew; } /* make an object named after someone listed in the scoreboard file */ @@ -1381,16 +1386,16 @@ mk_tt_object(objtype, x, y) int objtype; /* CORPSE or STATUE */ register int x, y; { - register struct obj *otmp, *otmp2; - boolean initialize_it; + register struct obj *otmp, *otmp2; + boolean initialize_it; - /* player statues never contain books */ - initialize_it = (objtype != STATUE); - if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) { - /* tt_oname will return null if the scoreboard is empty */ - if ((otmp2 = tt_oname(otmp)) != 0) otmp = otmp2; - } - return(otmp); + /* player statues never contain books */ + initialize_it = (objtype != STATUE); + if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) { + /* tt_oname will return null if the scoreboard is empty */ + if ((otmp2 = tt_oname(otmp)) != 0) otmp = otmp2; + } + return(otmp); } /* make a new corpse or statue, uninitialized if a statue (i.e. no books) */ @@ -1401,45 +1406,45 @@ struct permonst *ptr; int x, y; const char *nm; { - struct obj *otmp; - unsigned corpstatflags = (objtype != STATUE) ? - CORPSTAT_INIT : CORPSTAT_NONE; + struct obj *otmp; + unsigned corpstatflags = (objtype != STATUE) ? + CORPSTAT_INIT : CORPSTAT_NONE; - otmp = mkcorpstat(objtype, (struct monst *)0, ptr, - x, y, corpstatflags); - if (nm) - otmp = oname(otmp, nm); - return(otmp); + otmp = mkcorpstat(objtype, (struct monst *)0, ptr, + x, y, corpstatflags); + if (nm) + otmp = oname(otmp, nm); + return(otmp); } boolean is_flammable(otmp) register struct obj *otmp; { - int otyp = otmp->otyp; - int omat = objects[otyp].oc_material; + int otyp = otmp->otyp; + int omat = objects[otyp].oc_material; - /* Candles can be burned, but they're not flammable in the sense that - * they can't get fire damage and it makes no sense for them to be - * fireproofed. - */ - if (Is_candle(otmp)) - return FALSE; + /* Candles can be burned, but they're not flammable in the sense that + * they can't get fire damage and it makes no sense for them to be + * fireproofed. + */ + if (Is_candle(otmp)) + return FALSE; - if (objects[otyp].oc_oprop == FIRE_RES || otyp == WAN_FIRE) - return FALSE; + if (objects[otyp].oc_oprop == FIRE_RES || otyp == WAN_FIRE) + return FALSE; - return((boolean)((omat <= WOOD && omat != LIQUID) || omat == PLASTIC)); + return((boolean)((omat <= WOOD && omat != LIQUID) || omat == PLASTIC)); } boolean is_rottable(otmp) register struct obj *otmp; { - int otyp = otmp->otyp; + int otyp = otmp->otyp; - return((boolean)(objects[otyp].oc_material <= WOOD && - objects[otyp].oc_material != LIQUID)); + return((boolean)(objects[otyp].oc_material <= WOOD && + objects[otyp].oc_material != LIQUID)); } /* @@ -1456,7 +1461,7 @@ int x, y; register struct obj *otmp2 = level.objects[x][y]; if (otmp->where != OBJ_FREE) - panic("place_object: obj not free"); + panic("place_object: obj not free"); obj_no_longer_held(otmp); /* (could bypass this vision update if there is already a boulder here) */ @@ -1464,11 +1469,11 @@ int x, y; /* obj goes under boulders */ if (otmp2 && (otmp2->otyp == BOULDER)) { - otmp->nexthere = otmp2->nexthere; - otmp2->nexthere = otmp; + otmp->nexthere = otmp2->nexthere; + otmp2->nexthere = otmp; } else { - otmp->nexthere = otmp2; - level.objects[x][y] = otmp; + otmp->nexthere = otmp2; + level.objects[x][y] = otmp; } /* set the new object's location */ @@ -1493,18 +1498,18 @@ obj_ice_effects(x, y, do_buried) int x, y; boolean do_buried; { - struct obj *otmp; + struct obj *otmp; - for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) { - if (otmp->timed) obj_timer_checks(otmp, x, y, 0); - } - if (do_buried) { - for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) { - if (otmp->ox == x && otmp->oy == y) { - if (otmp->timed) obj_timer_checks(otmp, x, y, 0); - } - } - } + for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) { + if (otmp->timed) obj_timer_checks(otmp, x, y, 0); + } + if (do_buried) { + for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) { + if (otmp->ox == x && otmp->oy == y) { + if (otmp->timed) obj_timer_checks(otmp, x, y, 0); + } + } + } } /* @@ -1521,13 +1526,13 @@ struct obj *otmp; long age, retval = otmp->age; if (otmp->otyp == CORPSE && otmp->on_ice) { - /* Adjust the age; must be same as obj_timer_checks() for off ice*/ - age = monstermoves - otmp->age; - retval += age * (ROT_ICE_ADJUSTMENT-1) / ROT_ICE_ADJUSTMENT; - debugpline("The %s age has ice modifications:otmp->age = %ld, returning %ld.", - s_suffix(doname(otmp)),otmp->age, retval); - debugpline("Effective age of corpse: %ld.", - monstermoves - retval); + /* Adjust the age; must be same as obj_timer_checks() for off ice*/ + age = monstermoves - otmp->age; + retval += age * (ROT_ICE_ADJUSTMENT-1) / ROT_ICE_ADJUSTMENT; + debugpline("The %s age has ice modifications:otmp->age = %ld, returning %ld.", + s_suffix(doname(otmp)),otmp->age, retval); + debugpline("Effective age of corpse: %ld.", + monstermoves - retval); } return retval; } @@ -1546,54 +1551,54 @@ int force; /* 0 = no force so do checks, <0 = force off, >0 force on */ /* Check for corpses just placed on or in ice */ if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x,y)) { - tleft = stop_timer(action, obj_to_any(otmp)); - if (tleft == 0L) { - action = REVIVE_MON; - tleft = stop_timer(action, obj_to_any(otmp)); - } - if (tleft != 0L) { - long age; - - /* mark the corpse as being on ice */ - otmp->on_ice = 1; - debugpline("%s is now on ice at %d,%d.", The(xname(otmp)),x,y); - /* Adjust the time remaining */ - tleft *= ROT_ICE_ADJUSTMENT; - restart_timer = TRUE; - /* Adjust the age; time spent off ice needs to be multiplied - by the ice adjustment and subtracted from the age so that - later calculations behave as if it had been on ice during - that time (longwinded way of saying this is the inverse - of removing it from the ice and of peeking at its age). */ - age = monstermoves - otmp->age; - otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT); - } + tleft = stop_timer(action, obj_to_any(otmp)); + if (tleft == 0L) { + action = REVIVE_MON; + tleft = stop_timer(action, obj_to_any(otmp)); + } + if (tleft != 0L) { + long age; + + /* mark the corpse as being on ice */ + otmp->on_ice = 1; + debugpline("%s is now on ice at %d,%d.", The(xname(otmp)),x,y); + /* Adjust the time remaining */ + tleft *= ROT_ICE_ADJUSTMENT; + restart_timer = TRUE; + /* Adjust the age; time spent off ice needs to be multiplied + by the ice adjustment and subtracted from the age so that + later calculations behave as if it had been on ice during + that time (longwinded way of saying this is the inverse + of removing it from the ice and of peeking at its age). */ + age = monstermoves - otmp->age; + otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT); + } } /* Check for corpses coming off ice */ else if ((force < 0) || - (otmp->otyp == CORPSE && otmp->on_ice && - !((on_floor || buried) && is_ice(x,y)))) { - tleft = stop_timer(action, obj_to_any(otmp)); - if (tleft == 0L) { - action = REVIVE_MON; - tleft = stop_timer(action, obj_to_any(otmp)); - } - if (tleft != 0L) { - long age; - - otmp->on_ice = 0; - debugpline("%s is no longer on ice at %d,%d.", The(xname(otmp)),x,y); - /* Adjust the remaining time */ - tleft /= ROT_ICE_ADJUSTMENT; - restart_timer = TRUE; - /* Adjust the age */ - age = monstermoves - otmp->age; - otmp->age += age * (ROT_ICE_ADJUSTMENT-1) / ROT_ICE_ADJUSTMENT; - } + (otmp->otyp == CORPSE && otmp->on_ice && + !((on_floor || buried) && is_ice(x,y)))) { + tleft = stop_timer(action, obj_to_any(otmp)); + if (tleft == 0L) { + action = REVIVE_MON; + tleft = stop_timer(action, obj_to_any(otmp)); + } + if (tleft != 0L) { + long age; + + otmp->on_ice = 0; + debugpline("%s is no longer on ice at %d,%d.", The(xname(otmp)),x,y); + /* Adjust the remaining time */ + tleft /= ROT_ICE_ADJUSTMENT; + restart_timer = TRUE; + /* Adjust the age */ + age = monstermoves - otmp->age; + otmp->age += age * (ROT_ICE_ADJUSTMENT-1) / ROT_ICE_ADJUSTMENT; + } } /* now re-start the timer with the appropriate modifications */ if (restart_timer) - (void) start_timer(tleft, TIMER_OBJECT, action, obj_to_any(otmp)); + (void) start_timer(tleft, TIMER_OBJECT, action, obj_to_any(otmp)); } #undef ROT_ICE_ADJUSTMENT @@ -1606,12 +1611,12 @@ register struct obj *otmp; xchar y = otmp->oy; if (otmp->where != OBJ_FLOOR) - panic("remove_object: obj not on floor"); + panic("remove_object: obj not on floor"); extract_nexthere(otmp, &level.objects[x][y]); extract_nobj(otmp, &fobj); /* update vision iff this was the only boulder at its spot */ if (otmp->otyp == BOULDER && !sobj_at(BOULDER, x, y)) - unblock_point(x,y); /* vision */ + unblock_point(x,y); /* vision */ if (otmp->timed) obj_timer_checks(otmp,x,y,0); } @@ -1624,17 +1629,17 @@ struct monst *mtmp; boolean keeping_mon = (mtmp->mhp > 0); while ((otmp = mtmp->minvent) != 0) { - /* this has now become very similar to m_useupall()... */ - obj_extract_self(otmp); - if (otmp->owornmask) { - if (keeping_mon) { - if (otmp == mwep) mwepgone(mtmp), mwep = 0; - mtmp->misc_worn_check &= ~otmp->owornmask; - update_mon_intrinsics(mtmp, otmp, FALSE, TRUE); - } - otmp->owornmask = 0L; /* obfree() expects this */ - } - obfree(otmp, (struct obj *)0); /* dealloc_obj() isn't sufficient */ + /* this has now become very similar to m_useupall()... */ + obj_extract_self(otmp); + if (otmp->owornmask) { + if (keeping_mon) { + if (otmp == mwep) mwepgone(mtmp), mwep = 0; + mtmp->misc_worn_check &= ~otmp->owornmask; + update_mon_intrinsics(mtmp, otmp, FALSE, TRUE); + } + otmp->owornmask = 0L; /* obfree() expects this */ + } + obfree(otmp, (struct obj *)0); /* dealloc_obj() isn't sufficient */ } } @@ -1658,33 +1663,33 @@ obj_extract_self(obj) struct obj *obj; { switch (obj->where) { - case OBJ_FREE: - break; - case OBJ_FLOOR: - remove_object(obj); - break; - case OBJ_CONTAINED: - extract_nobj(obj, &obj->ocontainer->cobj); - container_weight(obj->ocontainer); - break; - case OBJ_INVENT: - freeinv(obj); - break; - case OBJ_MINVENT: - extract_nobj(obj, &obj->ocarry->minvent); - break; - case OBJ_MIGRATING: - extract_nobj(obj, &migrating_objs); - break; - case OBJ_BURIED: - extract_nobj(obj, &level.buriedobjlist); - break; - case OBJ_ONBILL: - extract_nobj(obj, &billobjs); - break; - default: - panic("obj_extract_self"); - break; + case OBJ_FREE: + break; + case OBJ_FLOOR: + remove_object(obj); + break; + case OBJ_CONTAINED: + extract_nobj(obj, &obj->ocontainer->cobj); + container_weight(obj->ocontainer); + break; + case OBJ_INVENT: + freeinv(obj); + break; + case OBJ_MINVENT: + extract_nobj(obj, &obj->ocarry->minvent); + break; + case OBJ_MIGRATING: + extract_nobj(obj, &migrating_objs); + break; + case OBJ_BURIED: + extract_nobj(obj, &level.buriedobjlist); + break; + case OBJ_ONBILL: + extract_nobj(obj, &billobjs); + break; + default: + panic("obj_extract_self"); + break; } } @@ -1698,13 +1703,13 @@ extract_nobj(obj, head_ptr) curr = *head_ptr; for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nobj) { - if (curr == obj) { - if (prev) - prev->nobj = curr->nobj; - else - *head_ptr = curr->nobj; - break; - } + if (curr == obj) { + if (prev) + prev->nobj = curr->nobj; + else + *head_ptr = curr->nobj; + break; + } } if (!curr) panic("extract_nobj: object lost"); obj->where = OBJ_FREE; @@ -1725,13 +1730,13 @@ extract_nexthere(obj, head_ptr) curr = *head_ptr; for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nexthere) { - if (curr == obj) { - if (prev) - prev->nexthere = curr->nexthere; - else - *head_ptr = curr->nexthere; - break; - } + if (curr == obj) { + if (prev) + prev->nexthere = curr->nexthere; + else + *head_ptr = curr->nexthere; + break; + } } if (!curr) panic("extract_nexthere: object lost"); } @@ -1750,12 +1755,12 @@ add_to_minv(mon, obj) struct obj *otmp; if (obj->where != OBJ_FREE) - panic("add_to_minv: obj not free"); + panic("add_to_minv: obj not free"); /* merge if possible */ for (otmp = mon->minvent; otmp; otmp = otmp->nobj) - if (merged(&otmp, &obj)) - return 1; /* obj merged and then free'd */ + if (merged(&otmp, &obj)) + return 1; /* obj merged and then free'd */ /* else insert; don't bother forcing it to end of chain */ obj->where = OBJ_MINVENT; obj->ocarry = mon; @@ -1775,13 +1780,13 @@ add_to_container(container, obj) struct obj *otmp; if (obj->where != OBJ_FREE) - panic("add_to_container: obj not free"); + panic("add_to_container: obj not free"); if (container->where != OBJ_INVENT && container->where != OBJ_MINVENT) - obj_no_longer_held(obj); + obj_no_longer_held(obj); /* merge if possible */ for (otmp = container->cobj; otmp; otmp = otmp->nobj) - if (merged(&otmp, &obj)) return (otmp); + if (merged(&otmp, &obj)) return (otmp); obj->where = OBJ_CONTAINED; obj->ocontainer = container; @@ -1795,7 +1800,7 @@ add_to_migration(obj) struct obj *obj; { if (obj->where != OBJ_FREE) - panic("add_to_migration: obj not free"); + panic("add_to_migration: obj not free"); obj->where = OBJ_MIGRATING; obj->nobj = migrating_objs; @@ -1807,7 +1812,7 @@ add_to_buried(obj) struct obj *obj; { if (obj->where != OBJ_FREE) - panic("add_to_buried: obj not free"); + panic("add_to_buried: obj not free"); obj->where = OBJ_BURIED; obj->nobj = level.buriedobjlist; @@ -1821,10 +1826,10 @@ container_weight(container) { container->owt = weight(container); if (container->where == OBJ_CONTAINED) - container_weight(container->ocontainer); + container_weight(container->ocontainer); /* else if (container->where == OBJ_INVENT) - recalculate load delay here ??? + recalculate load delay here ??? */ } @@ -1837,11 +1842,11 @@ dealloc_obj(obj) struct obj *obj; { if (obj->where != OBJ_FREE) - panic("dealloc_obj: obj not free"); + panic("dealloc_obj: obj not free"); /* free up any timers attached to the object */ if (obj->timed) - obj_stop_timers(obj); + obj_stop_timers(obj); /* * Free up any light sources attached to the object. @@ -1852,7 +1857,7 @@ dealloc_obj(obj) * attached to it (and also requires lamplit to be set). */ if (obj_sheds_light(obj)) - del_light_source(LS_OBJECT, obj_to_any(obj)); + del_light_source(LS_OBJECT, obj_to_any(obj)); if (obj == thrownobj) thrownobj = 0; if (obj == kickedobj) kickedobj = 0; @@ -1870,64 +1875,64 @@ boolean tipping; /* caller emptying entire contents; affects shop handling */ int objcount = 0; if (!horn || horn->otyp != HORN_OF_PLENTY) { - impossible("bad horn o' plenty"); + impossible("bad horn o' plenty"); } else if (horn->spe < 1) { - pline1(nothing_happens); + pline1(nothing_happens); } else { - struct obj *obj; - const char *what; - - consume_obj_charge(horn, !tipping); - if (!rn2(13)) { - obj = mkobj(POTION_CLASS, FALSE); - if (objects[obj->otyp].oc_magic) do { - obj->otyp = rnd_class(POT_BOOZE, POT_WATER); - } while (obj->otyp == POT_SICKNESS); - what = (obj->quan > 1L) ? "Some potions" : "A potion"; - } else { - obj = mkobj(FOOD_CLASS, FALSE); - if (obj->otyp == FOOD_RATION && !rn2(7)) - obj->otyp = LUMP_OF_ROYAL_JELLY; - what = "Some food"; - } - ++objcount; - pline("%s %s out.", what, vtense(what, "spill")); - obj->blessed = horn->blessed; - obj->cursed = horn->cursed; - obj->owt = weight(obj); - /* using a shop's horn of plenty entails a usage fee and also - confers ownership of the created item to the shopkeeper */ - if (horn->unpaid) - addtobill(obj, FALSE, FALSE, tipping); - /* if it ended up on bill, we don't want "(unpaid, N zorkids)" - being included in its formatted name during next message */ - iflags.suppress_price++; - if (!tipping) { - obj = hold_another_object(obj, u.uswallow ? - "Oops! %s out of your reach!" : - (Is_airlevel(&u.uz) || - Is_waterlevel(&u.uz) || - levl[u.ux][u.uy].typ < IRONBARS || - levl[u.ux][u.uy].typ >= ICE) ? - "Oops! %s away from you!" : - "Oops! %s to the floor!", - The(aobjnam(obj, "slip")), - (const char *)0); - } else { - /* assumes this is taking place at hero's location */ - if (!can_reach_floor(TRUE)) { - hitfloor(obj); /* does altar check, message, drop */ - } else { - if (IS_ALTAR(levl[u.ux][u.uy].typ)) - doaltarobj(obj); /* does its own drop message */ - else - pline("%s %s to the %s.", Doname2(obj), - otense(obj, "drop"), surface(u.ux, u.uy)); - dropy(obj); - } - } - iflags.suppress_price--; - if (horn->dknown) makeknown(HORN_OF_PLENTY); + struct obj *obj; + const char *what; + + consume_obj_charge(horn, !tipping); + if (!rn2(13)) { + obj = mkobj(POTION_CLASS, FALSE); + if (objects[obj->otyp].oc_magic) do { + obj->otyp = rnd_class(POT_BOOZE, POT_WATER); + } while (obj->otyp == POT_SICKNESS); + what = (obj->quan > 1L) ? "Some potions" : "A potion"; + } else { + obj = mkobj(FOOD_CLASS, FALSE); + if (obj->otyp == FOOD_RATION && !rn2(7)) + obj->otyp = LUMP_OF_ROYAL_JELLY; + what = "Some food"; + } + ++objcount; + pline("%s %s out.", what, vtense(what, "spill")); + obj->blessed = horn->blessed; + obj->cursed = horn->cursed; + obj->owt = weight(obj); + /* using a shop's horn of plenty entails a usage fee and also + confers ownership of the created item to the shopkeeper */ + if (horn->unpaid) + addtobill(obj, FALSE, FALSE, tipping); + /* if it ended up on bill, we don't want "(unpaid, N zorkids)" + being included in its formatted name during next message */ + iflags.suppress_price++; + if (!tipping) { + obj = hold_another_object(obj, u.uswallow ? + "Oops! %s out of your reach!" : + (Is_airlevel(&u.uz) || + Is_waterlevel(&u.uz) || + levl[u.ux][u.uy].typ < IRONBARS || + levl[u.ux][u.uy].typ >= ICE) ? + "Oops! %s away from you!" : + "Oops! %s to the floor!", + The(aobjnam(obj, "slip")), + (const char *)0); + } else { + /* assumes this is taking place at hero's location */ + if (!can_reach_floor(TRUE)) { + hitfloor(obj); /* does altar check, message, drop */ + } else { + if (IS_ALTAR(levl[u.ux][u.uy].typ)) + doaltarobj(obj); /* does its own drop message */ + else + pline("%s %s to the %s.", Doname2(obj), + otense(obj, "drop"), surface(u.ux, u.uy)); + dropy(obj); + } + } + iflags.suppress_price--; + if (horn->dknown) makeknown(HORN_OF_PLENTY); } return objcount; } @@ -1935,11 +1940,11 @@ boolean tipping; /* caller emptying entire contents; affects shop handling */ /* support for wizard-mode's `sanity_check' option */ static const char NEARDATA /* pline formats for insane_object() */ - ofmt0[] = "%s obj %s %s: %s", - ofmt3[] = "%s [not null] %s %s: %s", - /* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */ - mfmt1[] = "%s obj %s %s (%s)", - mfmt2[] = "%s obj %s %s (%s) *not*"; + ofmt0[] = "%s obj %s %s: %s", + ofmt3[] = "%s [not null] %s %s: %s", + /* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */ + mfmt1[] = "%s obj %s %s (%s)", + mfmt2[] = "%s obj %s %s (%s) *not*"; /* Check all object lists for consistency. */ void @@ -1954,19 +1959,19 @@ obj_sanity_check() those objects should have already been sanity checked via the floor list so container contents are skipped here */ for (x = 0; x < COLNO; x++) - for (y = 0; y < ROWNO; y++) - for (obj = level.objects[x][y]; obj; obj = obj->nexthere) { - /* should match ; <0,*> should always be empty */ - if (obj->where != OBJ_FLOOR || x == 0 || - obj->ox != x || obj->oy != y) { - char at_fmt[BUFSZ]; - - Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", - x, y, obj->ox, obj->oy); - insane_object(obj, at_fmt, "location sanity", - (struct monst *)0); - } - } + for (y = 0; y < ROWNO; y++) + for (obj = level.objects[x][y]; obj; obj = obj->nexthere) { + /* should match ; <0,*> should always be empty */ + if (obj->where != OBJ_FLOOR || x == 0 || + obj->ox != x || obj->oy != y) { + char at_fmt[BUFSZ]; + + Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", + x, y, obj->ox, obj->oy); + insane_object(obj, at_fmt, "location sanity", + (struct monst *)0); + } + } objlist_sanity(invent, OBJ_INVENT, "invent sanity"); objlist_sanity(migrating_objs, OBJ_MIGRATING, "migrating sanity"); @@ -1978,16 +1983,16 @@ obj_sanity_check() /* monsters temporarily in transit; they should have arrived with hero by the time we get called */ if (mydogs) { - pline("mydogs sanity [not empty]"); - mon_obj_sanity(mydogs, "mydogs minvent sanity"); + pline("mydogs sanity [not empty]"); + mon_obj_sanity(mydogs, "mydogs minvent sanity"); } /* objects temporarily freed from invent/floor lists; they should have arrived somewhere by the time we get called */ if (thrownobj) - insane_object(thrownobj, ofmt3, "thrownobj sanity", (struct monst *)0); + insane_object(thrownobj, ofmt3, "thrownobj sanity", (struct monst *)0); if (kickedobj) - insane_object(kickedobj, ofmt3, "kickedobj sanity", (struct monst *)0); + insane_object(kickedobj, ofmt3, "kickedobj sanity", (struct monst *)0); /* [how about current_wand too?] */ } @@ -2001,15 +2006,15 @@ const char *mesg; struct obj *obj; for (obj = objlist; obj; obj = obj->nobj) { - if (obj->where != wheretype) - insane_object(obj, ofmt0, mesg, (struct monst *)0); - if (Has_contents(obj)) { - if (wheretype == OBJ_ONBILL) - /* containers on shop bill should always be empty */ - insane_object(obj, "%s obj contains something! %s %s: %s", - mesg, (struct monst *)0); - check_contained(obj, mesg); - } + if (obj->where != wheretype) + insane_object(obj, ofmt0, mesg, (struct monst *)0); + if (Has_contents(obj)) { + if (wheretype == OBJ_ONBILL) + /* containers on shop bill should always be empty */ + insane_object(obj, "%s obj contains something! %s %s: %s", + mesg, (struct monst *)0); + check_contained(obj, mesg); + } } } @@ -2023,19 +2028,19 @@ const char *mesg; struct obj *obj; for (mon = monlist; mon; mon = mon->nmon) - for (obj = mon->minvent; obj; obj = obj->nobj) { - if (obj->where != OBJ_MINVENT) - insane_object(obj, mfmt1, mesg, mon); - if (obj->ocarry != mon) - insane_object(obj, mfmt2, mesg, mon); - check_contained(obj, mesg); - } + for (obj = mon->minvent; obj; obj = obj->nobj) { + if (obj->where != OBJ_MINVENT) + insane_object(obj, mfmt1, mesg, mon); + if (obj->ocarry != mon) + insane_object(obj, mfmt2, mesg, mon); + check_contained(obj, mesg); + } } /* This must stay consistent with the defines in obj.h. */ static const char *obj_state_names[NOBJ_STATES] = { - "free", "floor", "contained", "invent", - "minvent", "migrating", "buried", "onbill" + "free", "floor", "contained", "invent", + "minvent", "migrating", "buried", "onbill" }; STATIC_OVL const char * @@ -2048,8 +2053,8 @@ struct obj *obj; if (!obj) return "nowhere"; where = obj->where; if (where < 0 || where >= NOBJ_STATES || !obj_state_names[where]) { - Sprintf(unknown, "unknown[%d]", where); - return unknown; + Sprintf(unknown, "unknown[%d]", where); + return unknown; } return obj_state_names[where]; } @@ -2065,19 +2070,19 @@ struct monst *mon; objnm = monnm = "null!"; if (obj) { - iflags.override_ID++; - objnm = doname(obj); - iflags.override_ID--; + iflags.override_ID++; + objnm = doname(obj); + iflags.override_ID--; } if (mon || (strstri(mesg, "minvent") && !strstri(mesg, "contained"))) { - Strcat(strcpy(altfmt, fmt), " held by mon %s (%s)"); - if (mon) - monnm = x_monnam(mon, ARTICLE_A, (char *)0, EXACT_NAME, TRUE); - pline(altfmt, mesg, - fmt_ptr((genericptr_t)obj), where_name(obj), objnm, - fmt_ptr((genericptr_t)mon), monnm); + Strcat(strcpy(altfmt, fmt), " held by mon %s (%s)"); + if (mon) + monnm = x_monnam(mon, ARTICLE_A, (char *)0, EXACT_NAME, TRUE); + pline(altfmt, mesg, + fmt_ptr((genericptr_t)obj), where_name(obj), objnm, + fmt_ptr((genericptr_t)mon), monnm); } else { - pline(fmt, mesg, fmt_ptr((genericptr_t)obj), where_name(obj), objnm); + pline(fmt, mesg, fmt_ptr((genericptr_t)obj), where_name(obj), objnm); } } @@ -2095,35 +2100,137 @@ check_contained(container, mesg) /* change "invent sanity" to "contained invent sanity" but leave "nested contained invent sanity" as is */ if (!strstri(mesg, "contained")) - mesg = strcat(strcpy(mesgbuf, "contained "), mesg); + mesg = strcat(strcpy(mesgbuf, "contained "), mesg); for (obj = container->cobj; obj; obj = obj->nobj) { - /* catch direct cycle to avoid unbounded recursion */ - if (obj == container) - panic("failed sanity check: container holds itself"); - if (obj->where != OBJ_CONTAINED) - insane_object(obj, "%s obj %s %s: %s", mesg, (struct monst *)0); - else if (obj->ocontainer != container) - pline("%s obj %s in container %s, not %s", mesg, - fmt_ptr((genericptr_t)obj), - fmt_ptr((genericptr_t)obj->ocontainer), - fmt_ptr((genericptr_t)container)); - - if (Has_contents(obj)) { - /* catch most likely indirect cycle; we won't notice if - parent is present when something comes before it, or - notice more deeply embedded cycles (grandparent, &c) */ - if (obj->cobj == container) - panic("failed sanity check: container holds its parent"); - /* change "contained... sanity" to "nested contained... sanity" - and "nested contained..." to "nested nested contained..." */ - Strcpy(nestedmesg, "nested "); - copynchars(eos(nestedmesg), mesg, - (int)sizeof nestedmesg - (int)strlen(nestedmesg) - 1); - /* recursively check contents */ - check_contained(obj, nestedmesg); - } + /* catch direct cycle to avoid unbounded recursion */ + if (obj == container) + panic("failed sanity check: container holds itself"); + if (obj->where != OBJ_CONTAINED) + insane_object(obj, "%s obj %s %s: %s", mesg, (struct monst *)0); + else if (obj->ocontainer != container) + pline("%s obj %s in container %s, not %s", mesg, + fmt_ptr((genericptr_t)obj), + fmt_ptr((genericptr_t)obj->ocontainer), + fmt_ptr((genericptr_t)container)); + + if (Has_contents(obj)) { + /* catch most likely indirect cycle; we won't notice if + parent is present when something comes before it, or + notice more deeply embedded cycles (grandparent, &c) */ + if (obj->cobj == container) + panic("failed sanity check: container holds its parent"); + /* change "contained... sanity" to "nested contained... sanity" + and "nested contained..." to "nested nested contained..." */ + Strcpy(nestedmesg, "nested "); + copynchars(eos(nestedmesg), mesg, + (int)sizeof nestedmesg - (int)strlen(nestedmesg) - 1); + /* recursively check contents */ + check_contained(obj, nestedmesg); + } + } +} + + +/* + * wrapper to make "near this object" convenient + */ +struct obj* +obj_nexto(otmp) + struct obj* otmp; +{ + struct obj* otmp2 = NULL; + + if (otmp) { + otmp2 = obj_nexto_xy(otmp->otyp, otmp->ox, otmp->oy, otmp->o_id); + } else { + impossible("obj_nexto: wasn't given an object to check"); + } + + return otmp2; +} + + +/* + * looks for objects of a particular type next to x, y + * skips over oid if found (lets us avoid ourselves if + * we're looking for a second type of an existing object) + * + * TODO: return a list of all objects near us so we can more + * reliably predict which one we want to 'find' first + */ +struct obj* +obj_nexto_xy(otyp, x, y, oid) + int otyp, x, y, oid; +{ + struct obj* otmp; + int fx, fy, ex, ey; + short dx, dy; + + /* check under our "feet" first */ + otmp = sobj_at(otyp, x, y); + while (otmp) { + /* don't be clever and find ourselves */ + if (otmp->o_id != oid) { return otmp; } + otmp = nxtobj(otmp, otyp, TRUE); + } + + /* search in a random order */ + dx = (rn2(2) ? -1 : 1); + dy = (rn2(2) ? -1 : 1); + ex = x - dx; + ey = y - dy; + + for (fx = ex; abs(fx - ex) < 3; fx += dx) { + for (fy = ey; abs(fy - ey) < 3; fy += dy) { + /* 0, 0 was checked above */ + if (fx != x || fy != y) { + if (otmp = sobj_at(otyp, fx, fy)) { + return otmp; + } + } + } + } + + return NULL; +} + + +/* + * Causes one object to absorb another, smaller one of + * its own type, increasing weight accordingly. + * Returns the object that remains; frees the other. + */ +struct obj* +obj_meld(obj1, obj2) + struct obj **obj1, **obj2; +{ + struct obj *otmp1 = NULL, *otmp2 = NULL; + int extrawt = 0; + boolean reversed = FALSE; + + if (obj1 && obj2 && *obj1 && *obj2) { + otmp1 = *obj1; + otmp2 = *obj2; + + if ((otmp1->owt == otmp2->owt && rn2(2)) + || (otmp1->owt < otmp2->owt)) { + otmp2 = *obj1; otmp1 = *obj2; + reversed = TRUE; + } + + extrawt = otmp2->oeaten ? otmp2->oeaten : otmp2->owt; + otmp1->owt += extrawt; + otmp1->oeaten += otmp1->oeaten ? extrawt : 0; + obj_extract_self(otmp2); + dealloc_obj(otmp2); + if (reversed) { *obj1 = NULL; } else { *obj2 = NULL; } + return otmp1; } + + impossible("obj_meld: not called with two actual objects"); + return NULL; } + /*mkobj.c*/ diff --git a/src/mon.c b/src/mon.c index 8d616c9fa..ce04cc382 100644 --- a/src/mon.c +++ b/src/mon.c @@ -25,13 +25,13 @@ STATIC_DCL boolean FDECL(validvamp, (struct monst *,int *,int)); STATIC_DCL struct permonst *FDECL(accept_newcham_form, (int)); #define LEVEL_SPECIFIC_NOCORPSE(mdat) \ - (Is_rogue_level(&u.uz) || \ - (level.flags.graveyard && is_undead(mdat) && rn2(3))) + (Is_rogue_level(&u.uz) || \ + (level.flags.graveyard && is_undead(mdat) && rn2(3))) #if 0 /* part of the original warning code which was replaced in 3.3.1 */ const char *warnings[] = { - "white", "pink", "red", "ruby", "purple", "black" + "white", "pink", "red", "ruby", "purple", "black" }; #endif /* 0 */ @@ -44,31 +44,31 @@ int undead_to_corpse(mndx) int mndx; { - switch (mndx) { - case PM_KOBOLD_ZOMBIE: - case PM_KOBOLD_MUMMY: mndx = PM_KOBOLD; break; - case PM_DWARF_ZOMBIE: - case PM_DWARF_MUMMY: mndx = PM_DWARF; break; - case PM_GNOME_ZOMBIE: - case PM_GNOME_MUMMY: mndx = PM_GNOME; break; - case PM_ORC_ZOMBIE: - case PM_ORC_MUMMY: mndx = PM_ORC; break; - case PM_ELF_ZOMBIE: - case PM_ELF_MUMMY: mndx = PM_ELF; break; - case PM_VAMPIRE: - case PM_VAMPIRE_LORD: + switch (mndx) { + case PM_KOBOLD_ZOMBIE: + case PM_KOBOLD_MUMMY: mndx = PM_KOBOLD; break; + case PM_DWARF_ZOMBIE: + case PM_DWARF_MUMMY: mndx = PM_DWARF; break; + case PM_GNOME_ZOMBIE: + case PM_GNOME_MUMMY: mndx = PM_GNOME; break; + case PM_ORC_ZOMBIE: + case PM_ORC_MUMMY: mndx = PM_ORC; break; + case PM_ELF_ZOMBIE: + case PM_ELF_MUMMY: mndx = PM_ELF; break; + case PM_VAMPIRE: + case PM_VAMPIRE_LORD: #if 0 /* DEFERRED */ - case PM_VAMPIRE_MAGE: + case PM_VAMPIRE_MAGE: #endif - case PM_HUMAN_ZOMBIE: - case PM_HUMAN_MUMMY: mndx = PM_HUMAN; break; - case PM_GIANT_ZOMBIE: - case PM_GIANT_MUMMY: mndx = PM_GIANT; break; - case PM_ETTIN_ZOMBIE: - case PM_ETTIN_MUMMY: mndx = PM_ETTIN; break; - default: break; - } - return mndx; + case PM_HUMAN_ZOMBIE: + case PM_HUMAN_MUMMY: mndx = PM_HUMAN; break; + case PM_GIANT_ZOMBIE: + case PM_GIANT_MUMMY: mndx = PM_GIANT; break; + case PM_ETTIN_ZOMBIE: + case PM_ETTIN_MUMMY: mndx = PM_ETTIN; break; + default: break; + } + return mndx; } /* Convert the monster index of some monsters (such as quest guardians) @@ -81,33 +81,33 @@ int genus(mndx, mode) int mndx, mode; { - switch (mndx) { + switch (mndx) { /* Quest guardians */ - case PM_STUDENT: mndx = mode ? PM_ARCHEOLOGIST : PM_HUMAN; break; - case PM_CHIEFTAIN: mndx = mode ? PM_BARBARIAN : PM_HUMAN; break; - case PM_NEANDERTHAL: mndx = mode ? PM_CAVEMAN : PM_HUMAN; break; - case PM_ATTENDANT: mndx = mode ? PM_HEALER : PM_HUMAN; break; - case PM_PAGE: mndx = mode ? PM_KNIGHT : PM_HUMAN; break; - case PM_ABBOT: mndx = mode ? PM_MONK : PM_HUMAN; break; - case PM_ACOLYTE: mndx = mode ? PM_PRIEST : PM_HUMAN; break; - case PM_HUNTER: mndx = mode ? PM_RANGER : PM_HUMAN; break; - case PM_THUG: mndx = mode ? PM_ROGUE : PM_HUMAN; break; - case PM_ROSHI: mndx = mode ? PM_SAMURAI : PM_HUMAN; break; - case PM_GUIDE: mndx = mode ? PM_TOURIST : PM_HUMAN; break; - case PM_APPRENTICE: mndx = mode ? PM_WIZARD : PM_HUMAN; break; - case PM_WARRIOR: mndx = mode ? PM_VALKYRIE : PM_HUMAN; break; - default: - if (mndx >= LOW_PM && mndx < NUMMONS) { - struct permonst *ptr = &mons[mndx]; - if (is_human(ptr)) mndx = PM_HUMAN; - else if (is_elf(ptr)) mndx = PM_ELF; - else if (is_dwarf(ptr)) mndx = PM_DWARF; - else if (is_gnome(ptr)) mndx = PM_GNOME; - else if (is_orc(ptr)) mndx = PM_ORC; - } - break; - } - return mndx; + case PM_STUDENT: mndx = mode ? PM_ARCHEOLOGIST : PM_HUMAN; break; + case PM_CHIEFTAIN: mndx = mode ? PM_BARBARIAN : PM_HUMAN; break; + case PM_NEANDERTHAL: mndx = mode ? PM_CAVEMAN : PM_HUMAN; break; + case PM_ATTENDANT: mndx = mode ? PM_HEALER : PM_HUMAN; break; + case PM_PAGE: mndx = mode ? PM_KNIGHT : PM_HUMAN; break; + case PM_ABBOT: mndx = mode ? PM_MONK : PM_HUMAN; break; + case PM_ACOLYTE: mndx = mode ? PM_PRIEST : PM_HUMAN; break; + case PM_HUNTER: mndx = mode ? PM_RANGER : PM_HUMAN; break; + case PM_THUG: mndx = mode ? PM_ROGUE : PM_HUMAN; break; + case PM_ROSHI: mndx = mode ? PM_SAMURAI : PM_HUMAN; break; + case PM_GUIDE: mndx = mode ? PM_TOURIST : PM_HUMAN; break; + case PM_APPRENTICE: mndx = mode ? PM_WIZARD : PM_HUMAN; break; + case PM_WARRIOR: mndx = mode ? PM_VALKYRIE : PM_HUMAN; break; + default: + if (mndx >= LOW_PM && mndx < NUMMONS) { + struct permonst *ptr = &mons[mndx]; + if (is_human(ptr)) mndx = PM_HUMAN; + else if (is_elf(ptr)) mndx = PM_ELF; + else if (is_dwarf(ptr)) mndx = PM_DWARF; + else if (is_gnome(ptr)) mndx = PM_GNOME; + else if (is_orc(ptr)) mndx = PM_ORC; + } + break; + } + return mndx; } /* return monster index if chameleon, or NON_PM if not */ @@ -115,26 +115,26 @@ int pm_to_cham(mndx) int mndx; { - int mcham = NON_PM; + int mcham = NON_PM; - /* - * As of 3.5.0 we just check M2_SHAPESHIFTER instead of having a - * big switch statement with hardcoded shapeshifter types here. - */ - if (mndx >= LOW_PM && is_shapeshifter(&mons[mndx])) mcham = mndx; - return mcham; + /* + * As of 3.5.0 we just check M2_SHAPESHIFTER instead of having a + * big switch statement with hardcoded shapeshifter types here. + */ + if (mndx >= LOW_PM && is_shapeshifter(&mons[mndx])) mcham = mndx; + return mcham; } /* for deciding whether corpse will carry along full monster data */ #define KEEPTRAITS(mon) ((mon)->isshk || (mon)->mtame || \ - unique_corpstat(mon->data) || \ - is_reviver((mon)->data) || \ - /* normally leader the will be unique, */ \ - /* but he might have been polymorphed */ \ - (mon)->m_id == quest_status.leader_m_id || \ - /* special cancellation handling for these */ \ - (dmgtype((mon)->data, AD_SEDU) || \ - dmgtype((mon)->data, AD_SSEX))) + unique_corpstat(mon->data) || \ + is_reviver((mon)->data) || \ + /* normally leader the will be unique, */ \ + /* but he might have been polymorphed */ \ + (mon)->m_id == quest_status.leader_m_id || \ + /* special cancellation handling for these */ \ + (dmgtype((mon)->data, AD_SEDU) || \ + dmgtype((mon)->data, AD_SSEX))) /* Creates a monster corpse, a "special" corpse, or nothing if it doesn't * leave corpses. Monsters which leave "special" corpses should have @@ -146,140 +146,149 @@ make_corpse(mtmp,corpseflags) register struct monst *mtmp; unsigned corpseflags; { - register struct permonst *mdat = mtmp->data; - int num; - struct obj *obj = (struct obj *)0; - int x = mtmp->mx, y = mtmp->my; - int mndx = monsndx(mdat); - unsigned corpstatflags = corpseflags; - boolean burythem = ((corpstatflags & CORPSTAT_BURIED) != 0); - - switch(mndx) { - case PM_GRAY_DRAGON: - case PM_SILVER_DRAGON: + register struct permonst *mdat = mtmp->data; + int num; + struct obj *obj = (struct obj *)0; + struct obj* otmp = (struct obj*)0; + int x = mtmp->mx, y = mtmp->my; + int mndx = monsndx(mdat); + unsigned corpstatflags = corpseflags; + boolean burythem = ((corpstatflags & CORPSTAT_BURIED) != 0); + + switch(mndx) { + case PM_GRAY_DRAGON: + case PM_SILVER_DRAGON: #if 0 /* DEFERRED */ - case PM_SHIMMERING_DRAGON: + case PM_SHIMMERING_DRAGON: #endif - case PM_RED_DRAGON: - case PM_ORANGE_DRAGON: - case PM_WHITE_DRAGON: - case PM_BLACK_DRAGON: - case PM_BLUE_DRAGON: - case PM_GREEN_DRAGON: - case PM_YELLOW_DRAGON: - /* Make dragon scales. This assumes that the order of the */ - /* dragons is the same as the order of the scales. */ - if (!rn2(mtmp->mrevived ? 20 : 3)) { - num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON; - obj = mksobj_at(num, x, y, FALSE, FALSE); - obj->spe = 0; - obj->cursed = obj->blessed = FALSE; - } - goto default_1; - - case PM_WHITE_UNICORN: - case PM_GRAY_UNICORN: - case PM_BLACK_UNICORN: - if (mtmp->mrevived && rn2(2)) { - if (canseemon(mtmp)) - pline("%s recently regrown horn crumbles to dust.", - s_suffix(Monnam(mtmp))); - } else { - obj = mksobj_at(UNICORN_HORN, x, y, TRUE, FALSE); - if (obj && mtmp->mrevived) obj->degraded_horn = 1; - } - goto default_1; - case PM_LONG_WORM: - (void) mksobj_at(WORM_TOOTH, x, y, TRUE, FALSE); - goto default_1; - case PM_VAMPIRE: - case PM_VAMPIRE_LORD: - /* include mtmp in the mkcorpstat() call */ - num = undead_to_corpse(mndx); - corpstatflags |= CORPSTAT_INIT; - obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); - obj->age -= 100; /* this is an *OLD* corpse */ - break; - case PM_KOBOLD_MUMMY: - case PM_DWARF_MUMMY: - case PM_GNOME_MUMMY: - case PM_ORC_MUMMY: - case PM_ELF_MUMMY: - case PM_HUMAN_MUMMY: - case PM_GIANT_MUMMY: - case PM_ETTIN_MUMMY: - case PM_KOBOLD_ZOMBIE: - case PM_DWARF_ZOMBIE: - case PM_GNOME_ZOMBIE: - case PM_ORC_ZOMBIE: - case PM_ELF_ZOMBIE: - case PM_HUMAN_ZOMBIE: - case PM_GIANT_ZOMBIE: - case PM_ETTIN_ZOMBIE: - num = undead_to_corpse(mndx); - corpstatflags |= CORPSTAT_INIT; - obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); - obj->age -= 100; /* this is an *OLD* corpse */ - break; - case PM_IRON_GOLEM: - num = d(2,6); - while (num--) - obj = mksobj_at(IRON_CHAIN, x, y, TRUE, FALSE); - free_mname(mtmp); /* don't christen obj */ - break; - case PM_GLASS_GOLEM: - num = d(2,4); /* very low chance of creating all glass gems */ - while (num--) - obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE, FALSE); - free_mname(mtmp); - break; - case PM_CLAY_GOLEM: - obj = mksobj_at(ROCK, x, y, FALSE, FALSE); - obj->quan = (long)(rn2(20) + 50); - obj->owt = weight(obj); - free_mname(mtmp); - break; - case PM_STONE_GOLEM: - corpstatflags &= ~CORPSTAT_INIT; - obj = mkcorpstat(STATUE, (struct monst *)0, - mdat, x, y, corpstatflags); - break; - case PM_WOOD_GOLEM: - num = d(2,4); - while(num--) { - obj = mksobj_at(QUARTERSTAFF, x, y, TRUE, FALSE); - } - free_mname(mtmp); - break; - case PM_LEATHER_GOLEM: - num = d(2,4); - while(num--) - obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE, FALSE); - free_mname(mtmp); - break; - case PM_GOLD_GOLEM: - /* Good luck gives more coins */ - obj = mkgold((long)(200 - rnl(101)), x, y); - free_mname(mtmp); - break; - case PM_PAPER_GOLEM: - num = rnd(4); - while (num--) - obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE, FALSE); - free_mname(mtmp); - break; + case PM_RED_DRAGON: + case PM_ORANGE_DRAGON: + case PM_WHITE_DRAGON: + case PM_BLACK_DRAGON: + case PM_BLUE_DRAGON: + case PM_GREEN_DRAGON: + case PM_YELLOW_DRAGON: + /* Make dragon scales. This assumes that the order of the */ + /* dragons is the same as the order of the scales. */ + if (!rn2(mtmp->mrevived ? 20 : 3)) { + num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON; + obj = mksobj_at(num, x, y, FALSE, FALSE); + obj->spe = 0; + obj->cursed = obj->blessed = FALSE; + } + goto default_1; + + case PM_WHITE_UNICORN: + case PM_GRAY_UNICORN: + case PM_BLACK_UNICORN: + if (mtmp->mrevived && rn2(2)) { + if (canseemon(mtmp)) + pline("%s recently regrown horn crumbles to dust.", + s_suffix(Monnam(mtmp))); + } else { + obj = mksobj_at(UNICORN_HORN, x, y, TRUE, FALSE); + if (obj && mtmp->mrevived) obj->degraded_horn = 1; + } + goto default_1; + case PM_LONG_WORM: + (void) mksobj_at(WORM_TOOTH, x, y, TRUE, FALSE); + goto default_1; + case PM_VAMPIRE: + case PM_VAMPIRE_LORD: + /* include mtmp in the mkcorpstat() call */ + num = undead_to_corpse(mndx); + corpstatflags |= CORPSTAT_INIT; + obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); + obj->age -= 100; /* this is an *OLD* corpse */ + break; + case PM_KOBOLD_MUMMY: + case PM_DWARF_MUMMY: + case PM_GNOME_MUMMY: + case PM_ORC_MUMMY: + case PM_ELF_MUMMY: + case PM_HUMAN_MUMMY: + case PM_GIANT_MUMMY: + case PM_ETTIN_MUMMY: + case PM_KOBOLD_ZOMBIE: + case PM_DWARF_ZOMBIE: + case PM_GNOME_ZOMBIE: + case PM_ORC_ZOMBIE: + case PM_ELF_ZOMBIE: + case PM_HUMAN_ZOMBIE: + case PM_GIANT_ZOMBIE: + case PM_ETTIN_ZOMBIE: + num = undead_to_corpse(mndx); + corpstatflags |= CORPSTAT_INIT; + obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); + obj->age -= 100; /* this is an *OLD* corpse */ + break; + case PM_IRON_GOLEM: + num = d(2,6); + while (num--) + obj = mksobj_at(IRON_CHAIN, x, y, TRUE, FALSE); + free_mname(mtmp); /* don't christen obj */ + break; + case PM_GLASS_GOLEM: + num = d(2,4); /* very low chance of creating all glass gems */ + while (num--) + obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE, FALSE); + free_mname(mtmp); + break; + case PM_CLAY_GOLEM: + obj = mksobj_at(ROCK, x, y, FALSE, FALSE); + obj->quan = (long)(rn2(20) + 50); + obj->owt = weight(obj); + free_mname(mtmp); + break; + case PM_STONE_GOLEM: + corpstatflags &= ~CORPSTAT_INIT; + obj = mkcorpstat(STATUE, (struct monst *)0, + mdat, x, y, corpstatflags); + break; + case PM_WOOD_GOLEM: + num = d(2,4); + while(num--) { + obj = mksobj_at(QUARTERSTAFF, x, y, TRUE, FALSE); + } + free_mname(mtmp); + break; + case PM_LEATHER_GOLEM: + num = d(2,4); + while(num--) + obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE, FALSE); + free_mname(mtmp); + break; + case PM_GOLD_GOLEM: + /* Good luck gives more coins */ + obj = mkgold((long)(200 - rnl(101)), x, y); + free_mname(mtmp); + break; + case PM_PAPER_GOLEM: + num = rnd(4); + while (num--) + obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE, FALSE); + free_mname(mtmp); + break; /* expired puddings will congeal into a large blob like dragons, relies on the order remaining consistent */ case PM_GRAY_OOZE: case PM_BROWN_PUDDING: case PM_GREEN_SLIME: case PM_BLACK_PUDDING: + /* we have to do this here because most other places + * expect there to be an object coming back; not this one */ obj = mksobj_at(GLOB_OF_BLACK_PUDDING - (PM_BLACK_PUDDING - mndx), - x, y, TRUE, FALSE); + x, y, TRUE, FALSE); + + while ((obj && (otmp = obj_nexto(obj)) != (struct obj*)0)) { + pline("The %s coalesce.", makeplural(obj_typename(obj->otyp))); + obj = obj_meld(&obj, &otmp); + } free_mname(mtmp); - break; - default_1: - default: + return obj; + break; + default_1: + default: if (mvitals[mndx].mvflags & G_NOCORPSE) return (struct obj *)0; else { @@ -293,30 +302,30 @@ unsigned corpseflags; return obj; } } - break; - } - /* All special cases should precede the G_NOCORPSE check */ - - /* if polymorph or undead turning has killed this monster, - prevent the same attack beam from hitting its corpse */ - if (context.bypasses) bypass_obj(obj); - - if (has_mname(mtmp)) - obj = oname(obj, MNAME(mtmp)); - - /* Avoid "It was hidden under a green mold corpse!" - * during Blind combat. An unseen monster referred to as "it" - * could be killed and leave a corpse. If a hider then hid - * underneath it, you could be told the corpse type of a - * monster that you never knew was there without this. - * The code in hitmu() substitutes the word "something" - * if the corpses obj->dknown is 0. - */ - if (Blind && !sensemon(mtmp)) obj->dknown = 0; + break; + } + /* All special cases should precede the G_NOCORPSE check */ + + /* if polymorph or undead turning has killed this monster, + prevent the same attack beam from hitting its corpse */ + if (context.bypasses) bypass_obj(obj); + + if (has_mname(mtmp)) + obj = oname(obj, MNAME(mtmp)); + + /* Avoid "It was hidden under a green mold corpse!" + * during Blind combat. An unseen monster referred to as "it" + * could be killed and leave a corpse. If a hider then hid + * underneath it, you could be told the corpse type of a + * monster that you never knew was there without this. + * The code in hitmu() substitutes the word "something" + * if the corpses obj->dknown is 0. + */ + if (Blind && !sensemon(mtmp)) obj->dknown = 0; - stackobj(obj); - newsym(x, y); - return obj; + stackobj(obj); + newsym(x, y); + return obj; } /* check mtmp and water/lava for compatibility, 0 (survived), 1 (died) */ @@ -327,101 +336,101 @@ register struct monst *mtmp; boolean inpool, inlava, infountain; inpool = is_pool(mtmp->mx,mtmp->my) && - !is_flyer(mtmp->data) && !is_floater(mtmp->data); + !is_flyer(mtmp->data) && !is_floater(mtmp->data); inlava = is_lava(mtmp->mx,mtmp->my) && - !is_flyer(mtmp->data) && !is_floater(mtmp->data); + !is_flyer(mtmp->data) && !is_floater(mtmp->data); infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ); - /* Flying and levitation keeps our steed out of the liquid */ - /* (but not water-walking or swimming) */ - if (mtmp == u.usteed && (Flying || Levitation)) - return (0); + /* Flying and levitation keeps our steed out of the liquid */ + /* (but not water-walking or swimming) */ + if (mtmp == u.usteed && (Flying || Levitation)) + return (0); /* Gremlin multiplying won't go on forever since the hit points * keep going down, and when it gets to 1 hit point the clone * function will fail. */ if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) { - if (split_mon(mtmp, (struct monst *)0)) - dryup(mtmp->mx, mtmp->my, FALSE); - if (inpool) water_damage_chain(mtmp->minvent, FALSE); - return (0); + if (split_mon(mtmp, (struct monst *)0)) + dryup(mtmp->mx, mtmp->my, FALSE); + if (inpool) water_damage_chain(mtmp->minvent, FALSE); + return (0); } else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) { - int dam = d(2,6); - if (cansee(mtmp->mx,mtmp->my)) - pline("%s rusts.", Monnam(mtmp)); - mtmp->mhp -= dam; - if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam; - if (mtmp->mhp < 1) { - mondead(mtmp); - if (mtmp->mhp < 1) return (1); - } - water_damage_chain(mtmp->minvent, FALSE); - return (0); + int dam = d(2,6); + if (cansee(mtmp->mx,mtmp->my)) + pline("%s rusts.", Monnam(mtmp)); + mtmp->mhp -= dam; + if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam; + if (mtmp->mhp < 1) { + mondead(mtmp); + if (mtmp->mhp < 1) return (1); + } + water_damage_chain(mtmp->minvent, FALSE); + return (0); } 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 %s.", Monnam(mtmp), - mtmp->data == &mons[PM_WATER_ELEMENTAL] ? - "boils away" : "burns to a crisp"); - 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) { + /* + * 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 %s.", Monnam(mtmp), + mtmp->data == &mons[PM_WATER_ELEMENTAL] ? + "boils away" : "burns to a crisp"); + 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) { (void) fire_damage_chain(mtmp->minvent, FALSE, FALSE, mtmp->mx, mtmp->my); - (void) rloc(mtmp, FALSE); - return 0; - } - return (1); - } + (void) rloc(mtmp, FALSE); + 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... - */ - if (!is_clinger(mtmp->data) - && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { - if (cansee(mtmp->mx,mtmp->my)) { - pline("%s drowns.", Monnam(mtmp)); - } - if (u.ustuck && u.uswallow && u.ustuck == mtmp) { - /* This can happen after a purple worm plucks you off a - flying steed while you are over water. */ - pline("%s sinks as water rushes in and flushes you out.", - Monnam(mtmp)); - } - mondead(mtmp); - if (mtmp->mhp > 0) { - water_damage_chain(mtmp->minvent, FALSE); - (void) rloc(mtmp, FALSE); - return 0; - } - return (1); - } + /* 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... + */ + if (!is_clinger(mtmp->data) + && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { + if (cansee(mtmp->mx,mtmp->my)) { + pline("%s drowns.", Monnam(mtmp)); + } + if (u.ustuck && u.uswallow && u.ustuck == mtmp) { + /* This can happen after a purple worm plucks you off a + flying steed while you are over water. */ + pline("%s sinks as water rushes in and flushes you out.", + Monnam(mtmp)); + } + mondead(mtmp); + if (mtmp->mhp > 0) { + water_damage_chain(mtmp->minvent, FALSE); + (void) rloc(mtmp, FALSE); + return 0; + } + return (1); + } } else { - /* but eels have a difficult time outside */ - if (mtmp->data->mlet == S_EEL && !Is_waterlevel(&u.uz)) { - /* as mhp gets lower, the rate of further loss slows down */ - if (mtmp->mhp > 1 && rn2(mtmp->mhp) > rn2(8)) mtmp->mhp--; - monflee(mtmp, 2, FALSE, FALSE); - } + /* but eels have a difficult time outside */ + if (mtmp->data->mlet == S_EEL && !Is_waterlevel(&u.uz)) { + /* as mhp gets lower, the rate of further loss slows down */ + if (mtmp->mhp > 1 && rn2(mtmp->mhp) > rn2(8)) mtmp->mhp--; + monflee(mtmp, 2, FALSE, FALSE); + } } return (0); } @@ -438,22 +447,22 @@ struct monst *mon; * both adjustments have negligible effect on higher speeds. */ if (mon->mspeed == MSLOW) - mmove = (2 * mmove + 1) / 3; + mmove = (2 * mmove + 1) / 3; else if (mon->mspeed == MFAST) - mmove = (4 * mmove + 2) / 3; + mmove = (4 * mmove + 2) / 3; if (mon == u.usteed) { - if (u.ugallop && context.mv) { - /* average movement is 1.50 times normal */ - mmove = ((rn2(2) ? 4 : 5) * mmove) / 3; - } + if (u.ugallop && context.mv) { + /* average movement is 1.50 times normal */ + mmove = ((rn2(2) ? 4 : 5) * mmove) / 3; + } } else if (mmove) { - /* vary movement points allocated to slightly reduce predictability; - random increment (avg +2) exceeds random decrement (avg +1) by - a small amount; normal speed monsters will occasionally get an - extra move and slow ones won't be quite as slow */ - mmove += rn2(5) - rn2(3); /* + 0..4 - 0..2, average net +1 */ - if (mmove < 1) mmove = 1; + /* vary movement points allocated to slightly reduce predictability; + random increment (avg +2) exceeds random decrement (avg +1) by + a small amount; normal speed monsters will occasionally get an + extra move and slow ones won't be quite as slow */ + mmove += rn2(5) - rn2(3); /* + 0..4 - 0..2, average net +1 */ + if (mmove < 1) mmove = 1; } return mmove; @@ -468,36 +477,36 @@ mcalcdistress() struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; + if (DEADMONSTER(mtmp)) continue; - /* must check non-moving monsters once/turn in case - * they managed to end up in liquid */ - if (mtmp->data->mmove == 0) { - if (vision_full_recalc) vision_recalc(0); - if (minliquid(mtmp)) continue; - } + /* must check non-moving monsters once/turn in case + * they managed to end up in liquid */ + if (mtmp->data->mmove == 0) { + if (vision_full_recalc) vision_recalc(0); + if (minliquid(mtmp)) continue; + } - /* regenerate hit points */ - mon_regen(mtmp, FALSE); + /* regenerate hit points */ + mon_regen(mtmp, FALSE); - /* possibly polymorph shapechangers and lycanthropes */ - if (mtmp->cham >= LOW_PM) { - if (is_vampshifter(mtmp) || mtmp->data->mlet == S_VAMPIRE) - decide_to_shapeshift(mtmp,0); - else if (!rn2(6)) - (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); - } - were_change(mtmp); + /* possibly polymorph shapechangers and lycanthropes */ + if (mtmp->cham >= LOW_PM) { + if (is_vampshifter(mtmp) || mtmp->data->mlet == S_VAMPIRE) + decide_to_shapeshift(mtmp,0); + else if (!rn2(6)) + (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); + } + were_change(mtmp); - /* gradually time out temporary problems */ - if (mtmp->mblinded && !--mtmp->mblinded) - mtmp->mcansee = 1; - if (mtmp->mfrozen && !--mtmp->mfrozen) - mtmp->mcanmove = 1; - if (mtmp->mfleetim && !--mtmp->mfleetim) - mtmp->mflee = 0; + /* gradually time out temporary problems */ + if (mtmp->mblinded && !--mtmp->mblinded) + mtmp->mcansee = 1; + if (mtmp->mfrozen && !--mtmp->mfrozen) + mtmp->mcanmove = 1; + if (mtmp->mfleetim && !--mtmp->mfleetim) + mtmp->mflee = 0; - /* FIXME: mtmp->mlstmv ought to be updated here */ + /* FIXME: mtmp->mlstmv ought to be updated here */ } } @@ -528,81 +537,81 @@ movemon() for(mtmp = fmon; mtmp; mtmp = nmtmp) { #ifdef SAFERHANGUP - if (program_state.done_hup) { - somebody_can_move = FALSE; - break; - } + if (program_state.done_hup) { + somebody_can_move = FALSE; + break; + } #endif - nmtmp = mtmp->nmon; - /* one dead monster needs to perform a move after death: - vault guard whose temporary corridor is still on the map */ - if (mtmp->isgd && !mtmp->mx && mtmp->mhp <= 0) (void)gd_move(mtmp); - if (DEADMONSTER(mtmp)) continue; - - /* Find a monster that we have not treated yet. */ - if(mtmp->movement < NORMAL_SPEED) - continue; - - mtmp->movement -= NORMAL_SPEED; - if (mtmp->movement >= NORMAL_SPEED) - somebody_can_move = TRUE; - - if (vision_full_recalc) vision_recalc(0); /* vision! */ - - if (minliquid(mtmp)) continue; - - if (is_hider(mtmp->data)) { - /* unwatched mimics and piercers may hide again [MRS] */ - if(restrap(mtmp)) continue; - if(mtmp->m_ap_type == M_AP_FURNITURE || - mtmp->m_ap_type == M_AP_OBJECT) - continue; - if(mtmp->mundetected) continue; - } else if (mtmp->data->mlet == S_EEL && !mtmp->mundetected && - (mtmp->mflee || distu(mtmp->mx, mtmp->my) > 2) && - !canseemon(mtmp) && !rn2(4)) { - /* some eels end up stuck in isolated pools, where they - can't--or at least won't--move, so they never reach - their post-move chance to re-hide */ - if (hideunder(mtmp)) continue; - } - - /* continue if the monster died fighting */ - if (Conflict && !mtmp->iswiz && mtmp->mcansee) { - /* Note: - * Conflict does not take effect in the first round. - * Therefore, A monster when stepping into the area will - * get to swing at you. - * - * The call to fightm() must be _last_. The monster might - * have died if it returns 1. - */ - if (couldsee(mtmp->mx,mtmp->my) && - (distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) && - fightm(mtmp)) - continue; /* mon might have died */ - } - if(dochugw(mtmp)) /* otherwise just move the monster */ - continue; + nmtmp = mtmp->nmon; + /* one dead monster needs to perform a move after death: + vault guard whose temporary corridor is still on the map */ + if (mtmp->isgd && !mtmp->mx && mtmp->mhp <= 0) (void)gd_move(mtmp); + if (DEADMONSTER(mtmp)) continue; + + /* Find a monster that we have not treated yet. */ + if(mtmp->movement < NORMAL_SPEED) + continue; + + mtmp->movement -= NORMAL_SPEED; + if (mtmp->movement >= NORMAL_SPEED) + somebody_can_move = TRUE; + + if (vision_full_recalc) vision_recalc(0); /* vision! */ + + if (minliquid(mtmp)) continue; + + if (is_hider(mtmp->data)) { + /* unwatched mimics and piercers may hide again [MRS] */ + if(restrap(mtmp)) continue; + if(mtmp->m_ap_type == M_AP_FURNITURE || + mtmp->m_ap_type == M_AP_OBJECT) + continue; + if(mtmp->mundetected) continue; + } else if (mtmp->data->mlet == S_EEL && !mtmp->mundetected && + (mtmp->mflee || distu(mtmp->mx, mtmp->my) > 2) && + !canseemon(mtmp) && !rn2(4)) { + /* some eels end up stuck in isolated pools, where they + can't--or at least won't--move, so they never reach + their post-move chance to re-hide */ + if (hideunder(mtmp)) continue; + } + + /* continue if the monster died fighting */ + if (Conflict && !mtmp->iswiz && mtmp->mcansee) { + /* Note: + * Conflict does not take effect in the first round. + * Therefore, A monster when stepping into the area will + * get to swing at you. + * + * The call to fightm() must be _last_. The monster might + * have died if it returns 1. + */ + if (couldsee(mtmp->mx,mtmp->my) && + (distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) && + fightm(mtmp)) + continue; /* mon might have died */ + } + if(dochugw(mtmp)) /* otherwise just move the monster */ + continue; } if (any_light_source()) - vision_full_recalc = 1; /* in case a mon moved with a light source */ + vision_full_recalc = 1; /* in case a mon moved with a light source */ dmonsfree(); /* remove all dead monsters */ /* a monster may have levteleported player -dlc */ if (u.utotype) { - deferred_goto(); - /* changed levels, so these monsters are dormant */ - somebody_can_move = FALSE; + deferred_goto(); + /* changed levels, so these monsters are dormant */ + somebody_can_move = FALSE; } return somebody_can_move; } #define mstoning(obj) (ofood(obj) && \ - (touch_petrifies(&mons[(obj)->corpsenm]) || \ - (obj)->corpsenm == PM_MEDUSA)) + (touch_petrifies(&mons[(obj)->corpsenm]) || \ + (obj)->corpsenm == PM_MEDUSA)) /* * Maybe eat a metallic object (not just gold). @@ -613,311 +622,311 @@ movemon() */ int meatmetal(mtmp) - register struct monst *mtmp; -{ - register struct obj *otmp; - struct permonst *ptr; - int poly, grow, heal, mstone; - - /* If a pet, eating is handled separately, in dog.c */ - if (mtmp->mtame) return 0; - - /* Eats topmost metal object if it is there */ - for (otmp = level.objects[mtmp->mx][mtmp->my]; - otmp; otmp = otmp->nexthere) { - if (mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) - continue; - if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && - touch_artifact(otmp,mtmp)) { - if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) { - if (canseemon(mtmp) && flags.verbose) { - pline("%s eats %s!", - Monnam(mtmp), - distant_name(otmp,doname)); - } - /* The object's rustproofing is gone now */ - otmp->oerodeproof = 0; - mtmp->mstun = 1; - if (canseemon(mtmp) && flags.verbose) { - pline("%s spits %s out in disgust!", - Monnam(mtmp), distant_name(otmp,doname)); - } - /* KMH -- Don't eat indigestible/choking objects */ - } else if (otmp->otyp != AMULET_OF_STRANGULATION && - otmp->otyp != RIN_SLOW_DIGESTION) { - if (cansee(mtmp->mx,mtmp->my) && flags.verbose) - pline("%s eats %s!", Monnam(mtmp), - distant_name(otmp,doname)); - else if (flags.verbose) - You_hear("a crunching sound."); - mtmp->meating = otmp->owt/2 + 1; - /* Heal up to the object's weight in hp */ - if (mtmp->mhp < mtmp->mhpmax) { - mtmp->mhp += objects[otmp->otyp].oc_weight; - if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; - } - if(otmp == uball) { - unpunish(); - delobj(otmp); - } else if (otmp == uchain) { - unpunish(); /* frees uchain */ - } else { - poly = polyfodder(otmp); - grow = mlevelgain(otmp); - heal = mhealup(otmp); - mstone = mstoning(otmp); - delobj(otmp); - ptr = mtmp->data; - if (poly) { - if (newcham(mtmp, (struct permonst *)0, - FALSE, FALSE)) - ptr = mtmp->data; - } else if (grow) { - ptr = grow_up(mtmp, (struct monst *)0); - } else if (mstone) { - if (poly_when_stoned(ptr)) { - mon_to_stone(mtmp); - ptr = mtmp->data; - } else if (!resists_ston(mtmp)) { - if (canseemon(mtmp)) - pline("%s turns to stone!", Monnam(mtmp)); - monstone(mtmp); - ptr = (struct permonst *)0; - } - } else if (heal) { - mtmp->mhp = mtmp->mhpmax; - } - if (!ptr) return 2; /* it died */ - } - /* Left behind a pile? */ - if (rnd(25) < 3) - (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); - newsym(mtmp->mx, mtmp->my); - return 1; - } - } - } - return 0; + register struct monst *mtmp; +{ + register struct obj *otmp; + struct permonst *ptr; + int poly, grow, heal, mstone; + + /* If a pet, eating is handled separately, in dog.c */ + if (mtmp->mtame) return 0; + + /* Eats topmost metal object if it is there */ + for (otmp = level.objects[mtmp->mx][mtmp->my]; + otmp; otmp = otmp->nexthere) { + if (mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) + continue; + if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && + touch_artifact(otmp,mtmp)) { + if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) { + if (canseemon(mtmp) && flags.verbose) { + pline("%s eats %s!", + Monnam(mtmp), + distant_name(otmp,doname)); + } + /* The object's rustproofing is gone now */ + otmp->oerodeproof = 0; + mtmp->mstun = 1; + if (canseemon(mtmp) && flags.verbose) { + pline("%s spits %s out in disgust!", + Monnam(mtmp), distant_name(otmp,doname)); + } + /* KMH -- Don't eat indigestible/choking objects */ + } else if (otmp->otyp != AMULET_OF_STRANGULATION && + otmp->otyp != RIN_SLOW_DIGESTION) { + if (cansee(mtmp->mx,mtmp->my) && flags.verbose) + pline("%s eats %s!", Monnam(mtmp), + distant_name(otmp,doname)); + else if (flags.verbose) + You_hear("a crunching sound."); + mtmp->meating = otmp->owt/2 + 1; + /* Heal up to the object's weight in hp */ + if (mtmp->mhp < mtmp->mhpmax) { + mtmp->mhp += objects[otmp->otyp].oc_weight; + if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; + } + if(otmp == uball) { + unpunish(); + delobj(otmp); + } else if (otmp == uchain) { + unpunish(); /* frees uchain */ + } else { + poly = polyfodder(otmp); + grow = mlevelgain(otmp); + heal = mhealup(otmp); + mstone = mstoning(otmp); + delobj(otmp); + ptr = mtmp->data; + if (poly) { + if (newcham(mtmp, (struct permonst *)0, + FALSE, FALSE)) + ptr = mtmp->data; + } else if (grow) { + ptr = grow_up(mtmp, (struct monst *)0); + } else if (mstone) { + if (poly_when_stoned(ptr)) { + mon_to_stone(mtmp); + ptr = mtmp->data; + } else if (!resists_ston(mtmp)) { + if (canseemon(mtmp)) + pline("%s turns to stone!", Monnam(mtmp)); + monstone(mtmp); + ptr = (struct permonst *)0; + } + } else if (heal) { + mtmp->mhp = mtmp->mhpmax; + } + if (!ptr) return 2; /* it died */ + } + /* Left behind a pile? */ + if (rnd(25) < 3) + (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); + newsym(mtmp->mx, mtmp->my); + return 1; + } + } + } + return 0; } /* monster eats a pile of objects */ int meatobj(mtmp) /* for gelatinous cubes */ - register struct monst *mtmp; -{ - register struct obj *otmp, *otmp2; - struct permonst *ptr, *original_ptr = mtmp->data; - int poly, grow, heal, count = 0, ecount = 0; - char buf[BUFSZ]; - - buf[0] = '\0'; - /* If a pet, eating is handled separately, in dog.c */ - if (mtmp->mtame) return 0; - - /* eat organic objects, including cloth and wood, if present; - engulf others, except huge rocks and metal attached to player - [despite comment at top, doesn't assume that eater is a g.cube] */ - for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { - otmp2 = otmp->nexthere; - - /* touch senstive items */ - if (otmp->otyp == CORPSE && - is_rider(&mons[otmp->corpsenm])) { - /* Rider corpse isn't just inedible; can't engulf it either */ - (void)revive_corpse(otmp); - - /* untouchable (or inaccessible) items */ - } else if ((otmp->otyp == CORPSE && - touch_petrifies(&mons[otmp->corpsenm]) && - !resists_ston(mtmp)) || - /* don't engulf boulders and statues or ball&chain */ - otmp->oclass == ROCK_CLASS || - otmp == uball || otmp == uchain) { - /* do nothing--neither eaten nor engulfed */ - continue; - - /* inedible items -- engulf these */ - } else if (!is_organic(otmp) || - obj_resists(otmp, 5, 95) || - !touch_artifact(otmp, mtmp) || - /* redundant due to non-organic composition but - included for emphasis */ - (otmp->otyp == AMULET_OF_STRANGULATION || - otmp->otyp == RIN_SLOW_DIGESTION) || - /* cockatrice corpses handled above; this - touch_petrifies() check catches eggs */ - ((otmp->otyp == CORPSE || otmp->otyp == EGG) && - ((touch_petrifies(&mons[otmp->corpsenm]) && - !resists_ston(mtmp)) || - (otmp->corpsenm == PM_GREEN_SLIME && - !slimeproof(mtmp->data))))) { - /* engulf */ - ++ecount; - if (ecount == 1) - Sprintf(buf, "%s engulfs %s.", Monnam(mtmp), - distant_name(otmp,doname)); - else if (ecount == 2) - Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp)); - obj_extract_self(otmp); - (void) mpickobj(mtmp, otmp); /* slurp */ - - /* lastly, edible items; yum! */ - } else { - /* devour */ - ++count; - if (cansee(mtmp->mx,mtmp->my) && flags.verbose) - pline("%s eats %s!", Monnam(mtmp), - distant_name(otmp, doname)); - else if (flags.verbose) - You_hear("a slurping sound."); - /* Heal up to the object's weight in hp */ - if (mtmp->mhp < mtmp->mhpmax) { - mtmp->mhp += objects[otmp->otyp].oc_weight; - if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; - } - if (Has_contents(otmp)) { - register struct obj *otmp3; - /* contents of eaten containers become engulfed; this - is arbitrary, but otherwise g.cubes are too powerful */ - while ((otmp3 = otmp->cobj) != 0) { - obj_extract_self(otmp3); - if (otmp->otyp == ICE_BOX && otmp3->otyp == CORPSE) { - otmp3->age = monstermoves - otmp3->age; - start_corpse_timeout(otmp3); - } - (void) mpickobj(mtmp, otmp3); - } - } - poly = polyfodder(otmp); - grow = mlevelgain(otmp); - heal = mhealup(otmp); - delobj(otmp); /* munch */ - ptr = mtmp->data; - if (poly) { - if (newcham(mtmp, (struct permonst *)0, FALSE, FALSE)) - ptr = mtmp->data; - } else if (grow) { - ptr = grow_up(mtmp, (struct monst *)0); - } else if (heal) { - mtmp->mhp = mtmp->mhpmax; - } - /* in case it polymorphed or died */ - if (ptr != original_ptr) - return !ptr ? 2 : 1; - } - - /* Engulf & devour is instant, so don't set meating */ - if (mtmp->minvis) newsym(mtmp->mx, mtmp->my); - } - - if (ecount > 0) { - if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0]) - pline1(buf); - else if (flags.verbose) - You_hear("%s slurping sound%s.", - ecount == 1 ? "a" : "several", - ecount == 1 ? "" : "s"); - } - return ((count > 0) || (ecount > 0)) ? 1 : 0; + register struct monst *mtmp; +{ + register struct obj *otmp, *otmp2; + struct permonst *ptr, *original_ptr = mtmp->data; + int poly, grow, heal, count = 0, ecount = 0; + char buf[BUFSZ]; + + buf[0] = '\0'; + /* If a pet, eating is handled separately, in dog.c */ + if (mtmp->mtame) return 0; + + /* eat organic objects, including cloth and wood, if present; + engulf others, except huge rocks and metal attached to player + [despite comment at top, doesn't assume that eater is a g.cube] */ + for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { + otmp2 = otmp->nexthere; + + /* touch senstive items */ + if (otmp->otyp == CORPSE && + is_rider(&mons[otmp->corpsenm])) { + /* Rider corpse isn't just inedible; can't engulf it either */ + (void)revive_corpse(otmp); + + /* untouchable (or inaccessible) items */ + } else if ((otmp->otyp == CORPSE && + touch_petrifies(&mons[otmp->corpsenm]) && + !resists_ston(mtmp)) || + /* don't engulf boulders and statues or ball&chain */ + otmp->oclass == ROCK_CLASS || + otmp == uball || otmp == uchain) { + /* do nothing--neither eaten nor engulfed */ + continue; + + /* inedible items -- engulf these */ + } else if (!is_organic(otmp) || + obj_resists(otmp, 5, 95) || + !touch_artifact(otmp, mtmp) || + /* redundant due to non-organic composition but + included for emphasis */ + (otmp->otyp == AMULET_OF_STRANGULATION || + otmp->otyp == RIN_SLOW_DIGESTION) || + /* cockatrice corpses handled above; this + touch_petrifies() check catches eggs */ + ((otmp->otyp == CORPSE || otmp->otyp == EGG) && + ((touch_petrifies(&mons[otmp->corpsenm]) && + !resists_ston(mtmp)) || + (otmp->corpsenm == PM_GREEN_SLIME && + !slimeproof(mtmp->data))))) { + /* engulf */ + ++ecount; + if (ecount == 1) + Sprintf(buf, "%s engulfs %s.", Monnam(mtmp), + distant_name(otmp,doname)); + else if (ecount == 2) + Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp)); + obj_extract_self(otmp); + (void) mpickobj(mtmp, otmp); /* slurp */ + + /* lastly, edible items; yum! */ + } else { + /* devour */ + ++count; + if (cansee(mtmp->mx,mtmp->my) && flags.verbose) + pline("%s eats %s!", Monnam(mtmp), + distant_name(otmp, doname)); + else if (flags.verbose) + You_hear("a slurping sound."); + /* Heal up to the object's weight in hp */ + if (mtmp->mhp < mtmp->mhpmax) { + mtmp->mhp += objects[otmp->otyp].oc_weight; + if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; + } + if (Has_contents(otmp)) { + register struct obj *otmp3; + /* contents of eaten containers become engulfed; this + is arbitrary, but otherwise g.cubes are too powerful */ + while ((otmp3 = otmp->cobj) != 0) { + obj_extract_self(otmp3); + if (otmp->otyp == ICE_BOX && otmp3->otyp == CORPSE) { + otmp3->age = monstermoves - otmp3->age; + start_corpse_timeout(otmp3); + } + (void) mpickobj(mtmp, otmp3); + } + } + poly = polyfodder(otmp); + grow = mlevelgain(otmp); + heal = mhealup(otmp); + delobj(otmp); /* munch */ + ptr = mtmp->data; + if (poly) { + if (newcham(mtmp, (struct permonst *)0, FALSE, FALSE)) + ptr = mtmp->data; + } else if (grow) { + ptr = grow_up(mtmp, (struct monst *)0); + } else if (heal) { + mtmp->mhp = mtmp->mhpmax; + } + /* in case it polymorphed or died */ + if (ptr != original_ptr) + return !ptr ? 2 : 1; + } + + /* Engulf & devour is instant, so don't set meating */ + if (mtmp->minvis) newsym(mtmp->mx, mtmp->my); + } + + if (ecount > 0) { + if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0]) + pline1(buf); + else if (flags.verbose) + You_hear("%s slurping sound%s.", + ecount == 1 ? "a" : "several", + ecount == 1 ? "" : "s"); + } + return ((count > 0) || (ecount > 0)) ? 1 : 0; } void mpickgold(mtmp) - register struct monst *mtmp; + register struct monst *mtmp; { register struct obj *gold; int mat_idx; if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) { - mat_idx = objects[gold->otyp].oc_material; + mat_idx = objects[gold->otyp].oc_material; obj_extract_self(gold); add_to_minv(mtmp, gold); - if (cansee(mtmp->mx, mtmp->my) ) { - if (flags.verbose && !mtmp->isgd) - pline("%s picks up some %s.", Monnam(mtmp), - mat_idx == GOLD ? "gold" : "money"); - newsym(mtmp->mx, mtmp->my); - } + if (cansee(mtmp->mx, mtmp->my) ) { + if (flags.verbose && !mtmp->isgd) + pline("%s picks up some %s.", Monnam(mtmp), + mat_idx == GOLD ? "gold" : "money"); + newsym(mtmp->mx, mtmp->my); + } } } boolean mpickstuff(mtmp, str) - register struct monst *mtmp; - register const char *str; + register struct monst *mtmp; + register const char *str; { - register struct obj *otmp, *otmp2; + register struct obj *otmp, *otmp2; /* prevent shopkeepers from leaving the door of their shop */ - if(mtmp->isshk && inhishop(mtmp)) return FALSE; + if(mtmp->isshk && inhishop(mtmp)) return FALSE; - for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { - otmp2 = otmp->nexthere; + for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { + otmp2 = otmp->nexthere; /* Nymphs take everything. Most monsters don't pick up corpses. */ - if (!str ? searches_for_item(mtmp,otmp) : - !!(index(str, otmp->oclass))) { - if (otmp->otyp == CORPSE && mtmp->data->mlet != S_NYMPH && - /* let a handful of corpse types thru to can_carry() */ - !touch_petrifies(&mons[otmp->corpsenm]) && - otmp->corpsenm != PM_LIZARD && - !acidic(&mons[otmp->corpsenm])) continue; - if (!touch_artifact(otmp,mtmp)) continue; - if (!can_carry(mtmp,otmp)) continue; - if (is_pool(mtmp->mx,mtmp->my)) continue; - if (cansee(mtmp->mx,mtmp->my) && flags.verbose) - pline("%s picks up %s.", Monnam(mtmp), - (distu(mtmp->mx, mtmp->my) <= 5) ? - doname(otmp) : distant_name(otmp, doname)); - obj_extract_self(otmp); /* remove from floor */ - (void) mpickobj(mtmp, otmp); /* may merge and free otmp */ - m_dowear(mtmp, FALSE); - newsym(mtmp->mx, mtmp->my); - return TRUE; /* pick only one object */ - } - } - return FALSE; + if (!str ? searches_for_item(mtmp,otmp) : + !!(index(str, otmp->oclass))) { + if (otmp->otyp == CORPSE && mtmp->data->mlet != S_NYMPH && + /* let a handful of corpse types thru to can_carry() */ + !touch_petrifies(&mons[otmp->corpsenm]) && + otmp->corpsenm != PM_LIZARD && + !acidic(&mons[otmp->corpsenm])) continue; + if (!touch_artifact(otmp,mtmp)) continue; + if (!can_carry(mtmp,otmp)) continue; + if (is_pool(mtmp->mx,mtmp->my)) continue; + if (cansee(mtmp->mx,mtmp->my) && flags.verbose) + pline("%s picks up %s.", Monnam(mtmp), + (distu(mtmp->mx, mtmp->my) <= 5) ? + doname(otmp) : distant_name(otmp, doname)); + obj_extract_self(otmp); /* remove from floor */ + (void) mpickobj(mtmp, otmp); /* may merge and free otmp */ + m_dowear(mtmp, FALSE); + newsym(mtmp->mx, mtmp->my); + return TRUE; /* pick only one object */ + } + } + return FALSE; } int curr_mon_load(mtmp) register struct monst *mtmp; { - register int curload = 0; - register struct obj *obj; + register int curload = 0; + register struct obj *obj; - for(obj = mtmp->minvent; obj; obj = obj->nobj) { - if(obj->otyp != BOULDER || !throws_rocks(mtmp->data)) - curload += obj->owt; - } + for(obj = mtmp->minvent; obj; obj = obj->nobj) { + if(obj->otyp != BOULDER || !throws_rocks(mtmp->data)) + curload += obj->owt; + } - return curload; + return curload; } int max_mon_load(mtmp) register struct monst *mtmp; { - register long maxload; - /* Base monster carrying capacity is equal to human maximum - * carrying capacity, or half human maximum if not strong. - * (for a polymorphed player, the value used would be the - * non-polymorphed carrying capacity instead of max/half max). - * This is then modified by the ratio between the monster weights - * and human weights. Corpseless monsters are given a capacity - * proportional to their size instead of weight. - */ - if (!mtmp->data->cwt) - maxload = (MAX_CARR_CAP * (long)mtmp->data->msize) / MZ_HUMAN; - else if (!strongmonst(mtmp->data) - || (strongmonst(mtmp->data) && (mtmp->data->cwt > WT_HUMAN))) - maxload = (MAX_CARR_CAP * (long)mtmp->data->cwt) / WT_HUMAN; - else maxload = MAX_CARR_CAP; /*strong monsters w/cwt <= WT_HUMAN*/ + register long maxload; + /* Base monster carrying capacity is equal to human maximum + * carrying capacity, or half human maximum if not strong. + * (for a polymorphed player, the value used would be the + * non-polymorphed carrying capacity instead of max/half max). + * This is then modified by the ratio between the monster weights + * and human weights. Corpseless monsters are given a capacity + * proportional to their size instead of weight. + */ + if (!mtmp->data->cwt) + maxload = (MAX_CARR_CAP * (long)mtmp->data->msize) / MZ_HUMAN; + else if (!strongmonst(mtmp->data) + || (strongmonst(mtmp->data) && (mtmp->data->cwt > WT_HUMAN))) + maxload = (MAX_CARR_CAP * (long)mtmp->data->cwt) / WT_HUMAN; + else maxload = MAX_CARR_CAP; /*strong monsters w/cwt <= WT_HUMAN*/ - if (!strongmonst(mtmp->data)) maxload /= 2; + if (!strongmonst(mtmp->data)) maxload /= 2; - if (maxload < 1) maxload = 1; + if (maxload < 1) maxload = 1; - return (int) maxload; + return (int) maxload; } /* for restricting monsters' object-pickup */ @@ -926,256 +935,256 @@ can_carry(mtmp,otmp) struct monst *mtmp; struct obj *otmp; { - int otyp = otmp->otyp, newload = otmp->owt; - struct permonst *mdat = mtmp->data; - - if (notake(mdat)) return FALSE; /* can't carry anything */ - - if (otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && - !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp)) - return FALSE; - if (otyp == CORPSE && is_rider(&mons[otmp->corpsenm])) - return FALSE; - if (objects[otyp].oc_material == SILVER && mon_hates_silver(mtmp) && - (otyp != BELL_OF_OPENING || !is_covetous(mdat))) - return FALSE; - - /* Steeds don't pick up stuff (to avoid shop abuse) */ - if (mtmp == u.usteed) return (FALSE); - if (mtmp->isshk) return(TRUE); /* no limit */ - if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE); - /* otherwise players might find themselves obligated to violate - * their alignment if the monster takes something they need - */ + int otyp = otmp->otyp, newload = otmp->owt; + struct permonst *mdat = mtmp->data; + + if (notake(mdat)) return FALSE; /* can't carry anything */ + + if (otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && + !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp)) + return FALSE; + if (otyp == CORPSE && is_rider(&mons[otmp->corpsenm])) + return FALSE; + if (objects[otyp].oc_material == SILVER && mon_hates_silver(mtmp) && + (otyp != BELL_OF_OPENING || !is_covetous(mdat))) + return FALSE; + + /* Steeds don't pick up stuff (to avoid shop abuse) */ + if (mtmp == u.usteed) return (FALSE); + if (mtmp->isshk) return(TRUE); /* no limit */ + if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE); + /* otherwise players might find themselves obligated to violate + * their alignment if the monster takes something they need + */ - /* special--boulder throwers carry unlimited amounts of boulders */ - if (throws_rocks(mdat) && otyp == BOULDER) - return(TRUE); + /* special--boulder throwers carry unlimited amounts of boulders */ + if (throws_rocks(mdat) && otyp == BOULDER) + return(TRUE); - /* nymphs deal in stolen merchandise, but not boulders or statues */ - if (mdat->mlet == S_NYMPH) - return (boolean)(otmp->oclass != ROCK_CLASS); + /* nymphs deal in stolen merchandise, but not boulders or statues */ + if (mdat->mlet == S_NYMPH) + return (boolean)(otmp->oclass != ROCK_CLASS); - if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return FALSE; + if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return FALSE; - return(TRUE); + return(TRUE); } /* return number of acceptable neighbour positions */ int mfndpos(mon, poss, info, flag) - register struct monst *mon; - coord *poss; /* coord poss[9] */ - long *info; /* long info[9] */ - long flag; -{ - struct permonst *mdat = mon->data; - register xchar x,y,nx,ny; - register int cnt = 0; - register uchar ntyp; - uchar nowtyp; - boolean wantpool,poolok,lavaok,nodiag; - boolean rockok = FALSE, treeok = FALSE, thrudoor; - int maxx, maxy; - - x = mon->mx; - y = mon->my; - nowtyp = levl[x][y].typ; - - nodiag = NODIAG(mdat - mons); - wantpool = mdat->mlet == S_EEL; - poolok = is_flyer(mdat) || is_clinger(mdat) || - (is_swimmer(mdat) && !wantpool); - lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat); - thrudoor = ((flag & (ALLOW_WALL|BUSTDOOR)) != 0L); - if (flag & ALLOW_DIG) { - struct obj *mw_tmp; - - /* need to be specific about what can currently be dug */ - if (!needspick(mdat)) { - rockok = treeok = TRUE; - } else if ((mw_tmp = MON_WEP(mon)) && mw_tmp->cursed && - mon->weapon_check == NO_WEAPON_WANTED) { - rockok = is_pick(mw_tmp); - treeok = is_axe(mw_tmp); - } else { - rockok = (m_carrying(mon, PICK_AXE) || - (m_carrying(mon, DWARVISH_MATTOCK) && - !which_armor(mon, W_ARMS))); - treeok = (m_carrying(mon, AXE) || - (m_carrying(mon, BATTLE_AXE) && - !which_armor(mon, W_ARMS))); - } - thrudoor |= rockok || treeok; - } + register struct monst *mon; + coord *poss; /* coord poss[9] */ + long *info; /* long info[9] */ + long flag; +{ + struct permonst *mdat = mon->data; + register xchar x,y,nx,ny; + register int cnt = 0; + register uchar ntyp; + uchar nowtyp; + boolean wantpool,poolok,lavaok,nodiag; + boolean rockok = FALSE, treeok = FALSE, thrudoor; + int maxx, maxy; + + x = mon->mx; + y = mon->my; + nowtyp = levl[x][y].typ; + + nodiag = NODIAG(mdat - mons); + wantpool = mdat->mlet == S_EEL; + poolok = is_flyer(mdat) || is_clinger(mdat) || + (is_swimmer(mdat) && !wantpool); + lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat); + thrudoor = ((flag & (ALLOW_WALL|BUSTDOOR)) != 0L); + if (flag & ALLOW_DIG) { + struct obj *mw_tmp; + + /* need to be specific about what can currently be dug */ + if (!needspick(mdat)) { + rockok = treeok = TRUE; + } else if ((mw_tmp = MON_WEP(mon)) && mw_tmp->cursed && + mon->weapon_check == NO_WEAPON_WANTED) { + rockok = is_pick(mw_tmp); + treeok = is_axe(mw_tmp); + } else { + rockok = (m_carrying(mon, PICK_AXE) || + (m_carrying(mon, DWARVISH_MATTOCK) && + !which_armor(mon, W_ARMS))); + treeok = (m_carrying(mon, AXE) || + (m_carrying(mon, BATTLE_AXE) && + !which_armor(mon, W_ARMS))); + } + thrudoor |= rockok || treeok; + } nexttry: /* eels prefer the water, but if there is no water nearby, - they will crawl over land */ - if(mon->mconf) { - flag |= ALLOW_ALL; - flag &= ~NOTONL; - } - if(!mon->mcansee) - flag |= ALLOW_SSM; - maxx = min(x+1,COLNO-1); - maxy = min(y+1,ROWNO-1); - for(nx = max(1,x-1); nx <= maxx; nx++) - for(ny = max(0,y-1); ny <= maxy; ny++) { - if(nx == x && ny == y) continue; - if(IS_ROCK(ntyp = levl[nx][ny].typ) && - !((flag & ALLOW_WALL) && may_passwall(nx,ny)) && - !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue; - /* KMH -- Added iron bars */ - if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue; - if (IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) && - (((levl[nx][ny].doormask & D_CLOSED) && - !(flag & OPENDOOR)) || - ((levl[nx][ny].doormask & D_LOCKED) && - !(flag & UNLOCKDOOR))) && - !thrudoor) continue; - /* first diagonal checks (tight squeezes handled below) */ - if (nx != x && ny != y && (nodiag || - (IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) || - (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN)) || - ((IS_DOOR(nowtyp) || IS_DOOR(ntyp)) && Is_rogue_level(&u.uz)) || - /* mustn't pass between adjacent long worm segments, - but can attack that way */ - (m_at(x, ny) && m_at(nx, y) && worm_cross(x, y, nx, ny) && - !m_at(nx, ny) && (nx != u.ux || ny != u.uy)))) - continue; - if((is_pool(nx,ny) == wantpool || poolok) && - (lavaok || !is_lava(nx,ny))) { - int dispx, dispy; - boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat))); - boolean checkobj = OBJ_AT(nx,ny); - - /* Displacement also displaces the Elbereth/scare monster, - * as long as you are visible. - */ - if(Displaced && monseeu && (mon->mux==nx) && (mon->muy==ny)) { - dispx = u.ux; - dispy = u.uy; - } else { - dispx = nx; - dispy = ny; - } - - info[cnt] = 0; - if (onscary(dispx, dispy, mon)) { - if(!(flag & ALLOW_SSM)) continue; - info[cnt] |= ALLOW_SSM; - } - if((nx == u.ux && ny == u.uy) || - (nx == mon->mux && ny == mon->muy)) { - if (nx == u.ux && ny == u.uy) { - /* If it's right next to you, it found you, - * displaced or no. We must set mux and muy - * right now, so when we return we can tell - * that the ALLOW_U means to attack _you_ and - * not the image. - */ - mon->mux = u.ux; - mon->muy = u.uy; - } - if(!(flag & ALLOW_U)) continue; - info[cnt] |= ALLOW_U; - } else { - if(MON_AT(nx, ny)) { - struct monst *mtmp2 = m_at(nx, ny); - long mmflag = flag | mm_aggression(mon, mtmp2); - - if (mmflag & ALLOW_M) { - info[cnt] |= ALLOW_M; - if (mtmp2->mtame) { - if (!(mmflag & ALLOW_TM)) continue; - info[cnt] |= ALLOW_TM; - } - } else { - mmflag = flag | mm_displacement(mon, mtmp2); - if (!(mmflag & ALLOW_MDISP)) continue; - info[cnt] |= ALLOW_MDISP; - } - } - /* Note: ALLOW_SANCT only prevents movement, not */ - /* attack, into a temple. */ - if(level.flags.has_temple && - *in_rooms(nx, ny, TEMPLE) && - !*in_rooms(x, y, TEMPLE) && - in_your_sanctuary((struct monst *)0, nx, ny)) { - if(!(flag & ALLOW_SANCT)) continue; - info[cnt] |= ALLOW_SANCT; - } - } - if(checkobj && sobj_at(CLOVE_OF_GARLIC, nx, ny)) { - if(flag & NOGARLIC) continue; - info[cnt] |= NOGARLIC; - } - if(checkobj && sobj_at(BOULDER, nx, ny)) { - if(!(flag & ALLOW_ROCK)) continue; - info[cnt] |= ALLOW_ROCK; - } - if (monseeu && onlineu(nx,ny)) { - if(flag & NOTONL) continue; - info[cnt] |= NOTONL; - } - /* check for diagonal tight squeeze */ - if (nx != x && ny != y && bad_rock(mdat, x, ny) && - bad_rock(mdat, nx, y) && cant_squeeze_thru(mon)) - continue; - /* The monster avoids a particular type of trap if it's familiar - * with the trap type. Pets get ALLOW_TRAPS and checking is - * done in dogmove.c. In either case, "harmless" traps are - * neither avoided nor marked in info[]. - */ - { register struct trap *ttmp = t_at(nx, ny); - if(ttmp) { - if(ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0) { + they will crawl over land */ + if(mon->mconf) { + flag |= ALLOW_ALL; + flag &= ~NOTONL; + } + if(!mon->mcansee) + flag |= ALLOW_SSM; + maxx = min(x+1,COLNO-1); + maxy = min(y+1,ROWNO-1); + for(nx = max(1,x-1); nx <= maxx; nx++) + for(ny = max(0,y-1); ny <= maxy; ny++) { + if(nx == x && ny == y) continue; + if(IS_ROCK(ntyp = levl[nx][ny].typ) && + !((flag & ALLOW_WALL) && may_passwall(nx,ny)) && + !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue; + /* KMH -- Added iron bars */ + if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue; + if (IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) && + (((levl[nx][ny].doormask & D_CLOSED) && + !(flag & OPENDOOR)) || + ((levl[nx][ny].doormask & D_LOCKED) && + !(flag & UNLOCKDOOR))) && + !thrudoor) continue; + /* first diagonal checks (tight squeezes handled below) */ + if (nx != x && ny != y && (nodiag || + (IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) || + (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN)) || + ((IS_DOOR(nowtyp) || IS_DOOR(ntyp)) && Is_rogue_level(&u.uz)) || + /* mustn't pass between adjacent long worm segments, + but can attack that way */ + (m_at(x, ny) && m_at(nx, y) && worm_cross(x, y, nx, ny) && + !m_at(nx, ny) && (nx != u.ux || ny != u.uy)))) + continue; + if((is_pool(nx,ny) == wantpool || poolok) && + (lavaok || !is_lava(nx,ny))) { + int dispx, dispy; + boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat))); + boolean checkobj = OBJ_AT(nx,ny); + + /* Displacement also displaces the Elbereth/scare monster, + * as long as you are visible. + */ + if(Displaced && monseeu && (mon->mux==nx) && (mon->muy==ny)) { + dispx = u.ux; + dispy = u.uy; + } else { + dispx = nx; + dispy = ny; + } + + info[cnt] = 0; + if (onscary(dispx, dispy, mon)) { + if(!(flag & ALLOW_SSM)) continue; + info[cnt] |= ALLOW_SSM; + } + if((nx == u.ux && ny == u.uy) || + (nx == mon->mux && ny == mon->muy)) { + if (nx == u.ux && ny == u.uy) { + /* If it's right next to you, it found you, + * displaced or no. We must set mux and muy + * right now, so when we return we can tell + * that the ALLOW_U means to attack _you_ and + * not the image. + */ + mon->mux = u.ux; + mon->muy = u.uy; + } + if(!(flag & ALLOW_U)) continue; + info[cnt] |= ALLOW_U; + } else { + if(MON_AT(nx, ny)) { + struct monst *mtmp2 = m_at(nx, ny); + long mmflag = flag | mm_aggression(mon, mtmp2); + + if (mmflag & ALLOW_M) { + info[cnt] |= ALLOW_M; + if (mtmp2->mtame) { + if (!(mmflag & ALLOW_TM)) continue; + info[cnt] |= ALLOW_TM; + } + } else { + mmflag = flag | mm_displacement(mon, mtmp2); + if (!(mmflag & ALLOW_MDISP)) continue; + info[cnt] |= ALLOW_MDISP; + } + } + /* Note: ALLOW_SANCT only prevents movement, not */ + /* attack, into a temple. */ + if(level.flags.has_temple && + *in_rooms(nx, ny, TEMPLE) && + !*in_rooms(x, y, TEMPLE) && + in_your_sanctuary((struct monst *)0, nx, ny)) { + if(!(flag & ALLOW_SANCT)) continue; + info[cnt] |= ALLOW_SANCT; + } + } + if(checkobj && sobj_at(CLOVE_OF_GARLIC, nx, ny)) { + if(flag & NOGARLIC) continue; + info[cnt] |= NOGARLIC; + } + if(checkobj && sobj_at(BOULDER, nx, ny)) { + if(!(flag & ALLOW_ROCK)) continue; + info[cnt] |= ALLOW_ROCK; + } + if (monseeu && onlineu(nx,ny)) { + if(flag & NOTONL) continue; + info[cnt] |= NOTONL; + } + /* check for diagonal tight squeeze */ + if (nx != x && ny != y && bad_rock(mdat, x, ny) && + bad_rock(mdat, nx, y) && cant_squeeze_thru(mon)) + continue; + /* The monster avoids a particular type of trap if it's familiar + * with the trap type. Pets get ALLOW_TRAPS and checking is + * done in dogmove.c. In either case, "harmless" traps are + * neither avoided nor marked in info[]. + */ + { register struct trap *ttmp = t_at(nx, ny); + if(ttmp) { + if(ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0) { impossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp); - continue; - } - if ((ttmp->ttyp != RUST_TRAP - || mdat == &mons[PM_IRON_GOLEM]) - && ttmp->ttyp != STATUE_TRAP - && ((ttmp->ttyp != PIT - && ttmp->ttyp != SPIKED_PIT - && ttmp->ttyp != TRAPDOOR - && ttmp->ttyp != HOLE) - || (!is_flyer(mdat) - && !is_floater(mdat) - && !is_clinger(mdat)) - || Sokoban) - && (ttmp->ttyp != SLP_GAS_TRAP || - !resists_sleep(mon)) - && (ttmp->ttyp != BEAR_TRAP || - (mdat->msize > MZ_SMALL && - !amorphous(mdat) && !is_flyer(mdat) && - !is_whirly(mdat) && !unsolid(mdat))) - && (ttmp->ttyp != FIRE_TRAP || - !resists_fire(mon)) - && (ttmp->ttyp != SQKY_BOARD || !is_flyer(mdat)) - && (ttmp->ttyp != WEB || (!amorphous(mdat) && - !webmaker(mdat))) - && (ttmp->ttyp != ANTI_MAGIC || - !resists_magm(mon)) - ) { - if (!(flag & ALLOW_TRAPS)) { - if (mon->mtrapseen & (1L << (ttmp->ttyp - 1))) - continue; - } - info[cnt] |= ALLOW_TRAPS; - } - } - } - poss[cnt].x = nx; - poss[cnt].y = ny; - cnt++; - } - } - if(!cnt && wantpool && !is_pool(x,y)) { - wantpool = FALSE; - goto nexttry; - } - return(cnt); + continue; + } + if ((ttmp->ttyp != RUST_TRAP + || mdat == &mons[PM_IRON_GOLEM]) + && ttmp->ttyp != STATUE_TRAP + && ((ttmp->ttyp != PIT + && ttmp->ttyp != SPIKED_PIT + && ttmp->ttyp != TRAPDOOR + && ttmp->ttyp != HOLE) + || (!is_flyer(mdat) + && !is_floater(mdat) + && !is_clinger(mdat)) + || Sokoban) + && (ttmp->ttyp != SLP_GAS_TRAP || + !resists_sleep(mon)) + && (ttmp->ttyp != BEAR_TRAP || + (mdat->msize > MZ_SMALL && + !amorphous(mdat) && !is_flyer(mdat) && + !is_whirly(mdat) && !unsolid(mdat))) + && (ttmp->ttyp != FIRE_TRAP || + !resists_fire(mon)) + && (ttmp->ttyp != SQKY_BOARD || !is_flyer(mdat)) + && (ttmp->ttyp != WEB || (!amorphous(mdat) && + !webmaker(mdat))) + && (ttmp->ttyp != ANTI_MAGIC || + !resists_magm(mon)) + ) { + if (!(flag & ALLOW_TRAPS)) { + if (mon->mtrapseen & (1L << (ttmp->ttyp - 1))) + continue; + } + info[cnt] |= ALLOW_TRAPS; + } + } + } + poss[cnt].x = nx; + poss[cnt].y = ny; + cnt++; + } + } + if(!cnt && wantpool && !is_pool(x,y)) { + wantpool = FALSE; + goto nexttry; + } + return(cnt); } /* Monster against monster special attacks; for the specified monster @@ -1186,43 +1195,43 @@ impossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp); STATIC_OVL long mm_aggression(magr, mdef) struct monst *magr, /* monster that is currently deciding where to move */ - *mdef; /* another monster which is next to it */ + *mdef; /* another monster which is next to it */ { - /* supposedly purple worms are attracted to shrieking because they - like to eat shriekers, so attack the latter when feasible */ - if (magr->data == &mons[PM_PURPLE_WORM] && - mdef->data == &mons[PM_SHRIEKER]) - return ALLOW_M|ALLOW_TM; - /* Various other combinations such as dog vs cat, cat vs rat, and - elf vs orc have been suggested. For the time being we don't - support those. */ - return 0L; + /* supposedly purple worms are attracted to shrieking because they + like to eat shriekers, so attack the latter when feasible */ + if (magr->data == &mons[PM_PURPLE_WORM] && + mdef->data == &mons[PM_SHRIEKER]) + return ALLOW_M|ALLOW_TM; + /* Various other combinations such as dog vs cat, cat vs rat, and + elf vs orc have been suggested. For the time being we don't + support those. */ + return 0L; } /* Monster displacing another monster out of the way */ STATIC_OVL long mm_displacement(magr, mdef) struct monst *magr, /* monster that is currently deciding where to move */ - *mdef; /* another monster which is next to it */ -{ - struct permonst *pa = magr->data, - *pd = mdef->data; - - /* if attacker can't barge through, there's nothing to do; - or if defender can barge through too, don't let attacker - do so, otherwise they might just end up swapping places - again when defender gets its chance to move */ - if ((pa->mflags3 & M3_DISPLACES) != 0 && - (pd->mflags3 & M3_DISPLACES) == 0 && - /* no displacing grid bugs diagonally */ - !(magr->mx != mdef->mx && magr->my != mdef->my && - NODIAG(monsndx(pd))) && - /* no displacing trapped monsters or multi-location longworms */ - !mdef->mtrapped && (!mdef->wormno || !count_wsegs(mdef)) && - /* riders can move anything; others, same size or smaller only */ - (is_rider(pa) || pa->msize >= pd->msize)) - return ALLOW_MDISP; - return 0L; + *mdef; /* another monster which is next to it */ +{ + struct permonst *pa = magr->data, + *pd = mdef->data; + + /* if attacker can't barge through, there's nothing to do; + or if defender can barge through too, don't let attacker + do so, otherwise they might just end up swapping places + again when defender gets its chance to move */ + if ((pa->mflags3 & M3_DISPLACES) != 0 && + (pd->mflags3 & M3_DISPLACES) == 0 && + /* no displacing grid bugs diagonally */ + !(magr->mx != mdef->mx && magr->my != mdef->my && + NODIAG(monsndx(pd))) && + /* no displacing trapped monsters or multi-location longworms */ + !mdef->mtrapped && (!mdef->wormno || !count_wsegs(mdef)) && + /* riders can move anything; others, same size or smaller only */ + (is_rider(pa) || pa->msize >= pd->msize)) + return ALLOW_MDISP; + return 0L; } boolean @@ -1231,10 +1240,10 @@ register struct monst *mon; register int x,y; /* Is the square close enough for the monster to move or attack into? */ { - register int distance = dist2(mon->mx, mon->my, x, y); + register int distance = dist2(mon->mx, mon->my, x, y); - if (distance == 2 && NODIAG(mon->data - mons)) return 0; - return((boolean)(distance < 3)); + if (distance == 2 && NODIAG(mon->data - mons)) return 0; + return((boolean)(distance < 3)); } /* really free dead monsters */ @@ -1245,18 +1254,18 @@ dmonsfree() int count = 0; for (mtmp = &fmon; *mtmp;) { - freetmp = *mtmp; - if (freetmp->mhp <= 0 && !freetmp->isgd) { - *mtmp = freetmp->nmon; - dealloc_monst(freetmp); - count++; - } else - mtmp = &(freetmp->nmon); + freetmp = *mtmp; + if (freetmp->mhp <= 0 && !freetmp->isgd) { + *mtmp = freetmp->nmon; + dealloc_monst(freetmp); + count++; + } else + mtmp = &(freetmp->nmon); } if (count != iflags.purge_monsters) - impossible("dmonsfree: %d removed doesn't match %d pending", - count, iflags.purge_monsters); + impossible("dmonsfree: %d removed doesn't match %d pending", + count, iflags.purge_monsters); iflags.purge_monsters = 0; } @@ -1269,9 +1278,9 @@ register struct monst *mtmp, *mtmp2; /* transfer the monster's inventory */ for (otmp = mtmp2->minvent; otmp; otmp = otmp->nobj) { - if (otmp->where != OBJ_MINVENT || otmp->ocarry != mtmp) - debugpline("replmon: minvent inconsistency"); - otmp->ocarry = mtmp2; + if (otmp->where != OBJ_MINVENT || otmp->ocarry != mtmp) + debugpline("replmon: minvent inconsistency"); + otmp->ocarry = mtmp2; } mtmp->minvent = 0; @@ -1282,14 +1291,14 @@ register struct monst *mtmp, *mtmp2; if (mtmp != u.usteed) /* don't place steed onto the map */ place_monster(mtmp2, mtmp2->mx, mtmp2->my); if (mtmp2->wormno) /* update level.monsters[wseg->wx][wseg->wy] */ - place_wsegs(mtmp2); /* locations to mtmp2 not mtmp. */ + place_wsegs(mtmp2); /* locations to mtmp2 not mtmp. */ if (emits_light(mtmp2->data)) { - /* since this is so rare, we don't have any `mon_move_light_source' */ - new_light_source(mtmp2->mx, mtmp2->my, - emits_light(mtmp2->data), - LS_MONSTER, monst_to_any(mtmp2)); - /* here we rely on the fact that `mtmp' hasn't actually been deleted */ - del_light_source(LS_MONSTER, monst_to_any(mtmp)); + /* since this is so rare, we don't have any `mon_move_light_source' */ + new_light_source(mtmp2->mx, mtmp2->my, + emits_light(mtmp2->data), + LS_MONSTER, monst_to_any(mtmp2)); + /* here we rely on the fact that `mtmp' hasn't actually been deleted */ + del_light_source(LS_MONSTER, monst_to_any(mtmp)); } mtmp2->nmon = fmon; fmon = mtmp2; @@ -1308,110 +1317,110 @@ relmon(mon, monst_list) register struct monst *mon; struct monst **monst_list; /* &migrating_mons or &mydogs or null */ { - register struct monst *mtmp; - boolean unhide = (monst_list != 0); - int mx = mon->mx, my = mon->my; - - if (!fmon) panic("relmon: no fmon available."); - - if (unhide) { - /* can't remain hidden across level changes (exception: wizard - clone can continue imitating some other monster form); also, - might be imitating a boulder so need line-of-sight unblocking */ - mon->mundetected = 0; - if (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER) - seemimic(mon); - } + register struct monst *mtmp; + boolean unhide = (monst_list != 0); + int mx = mon->mx, my = mon->my; + + if (!fmon) panic("relmon: no fmon available."); + + if (unhide) { + /* can't remain hidden across level changes (exception: wizard + clone can continue imitating some other monster form); also, + might be imitating a boulder so need line-of-sight unblocking */ + mon->mundetected = 0; + if (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER) + seemimic(mon); + } - remove_monster(mx, my); + remove_monster(mx, my); - if (mon == fmon) { - fmon = fmon->nmon; - } else { - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) - if (mtmp->nmon == mon) break; + if (mon == fmon) { + fmon = fmon->nmon; + } else { + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + if (mtmp->nmon == mon) break; - if (mtmp) mtmp->nmon = mon->nmon; - else panic("relmon: mon not in list."); - } + if (mtmp) mtmp->nmon = mon->nmon; + else panic("relmon: mon not in list."); + } - if (unhide) { - newsym(mx, my); - /* insert into mydogs or migrating_mons */ - mon->nmon = *monst_list; - *monst_list = mon; - } else { - /* orphan has no next monster */ - mon->nmon = 0; - } + if (unhide) { + newsym(mx, my); + /* insert into mydogs or migrating_mons */ + mon->nmon = *monst_list; + *monst_list = mon; + } else { + /* orphan has no next monster */ + mon->nmon = 0; + } } void copy_mextra(mtmp2, mtmp1) struct monst *mtmp2, *mtmp1; { - if(!mtmp2 || !mtmp1 || !mtmp1->mextra) return; - - if (!mtmp2->mextra) mtmp2->mextra = newmextra(); - if (MNAME(mtmp1)) { - new_mname(mtmp2, (int)strlen(MNAME(mtmp1)) + 1); - Strcpy(MNAME(mtmp2), MNAME(mtmp1)); - } - if (EGD(mtmp1)) { - if (!EGD(mtmp2)) newegd(mtmp2); - (void)memcpy((genericptr_t)EGD(mtmp2), - (genericptr_t)EGD(mtmp1), - sizeof(struct egd)); - } - if (EPRI(mtmp1)) { - if (!EPRI(mtmp2)) newepri(mtmp2); - (void)memcpy((genericptr_t)EPRI(mtmp2), - (genericptr_t)EPRI(mtmp1), - sizeof(struct epri)); - } - if (ESHK(mtmp1)) { - if (!ESHK(mtmp2)) neweshk(mtmp2); - (void)memcpy((genericptr_t)ESHK(mtmp2), - (genericptr_t)ESHK(mtmp1), - sizeof(struct eshk)); - } - if (EMIN(mtmp1)) { - if (!EMIN(mtmp2)) newemin(mtmp2); - (void)memcpy((genericptr_t)EMIN(mtmp2), - (genericptr_t)EMIN(mtmp1), - sizeof(struct emin)); - } - if (EDOG(mtmp1)) { - if (!EDOG(mtmp2)) newedog(mtmp2); - (void)memcpy((genericptr_t)EDOG(mtmp2), - (genericptr_t)EDOG(mtmp1), - sizeof(struct edog)); - } - if (has_mcorpsenm(mtmp1)) MCORPSENM(mtmp2) = MCORPSENM(mtmp1); + if(!mtmp2 || !mtmp1 || !mtmp1->mextra) return; + + if (!mtmp2->mextra) mtmp2->mextra = newmextra(); + if (MNAME(mtmp1)) { + new_mname(mtmp2, (int)strlen(MNAME(mtmp1)) + 1); + Strcpy(MNAME(mtmp2), MNAME(mtmp1)); + } + if (EGD(mtmp1)) { + if (!EGD(mtmp2)) newegd(mtmp2); + (void)memcpy((genericptr_t)EGD(mtmp2), + (genericptr_t)EGD(mtmp1), + sizeof(struct egd)); + } + if (EPRI(mtmp1)) { + if (!EPRI(mtmp2)) newepri(mtmp2); + (void)memcpy((genericptr_t)EPRI(mtmp2), + (genericptr_t)EPRI(mtmp1), + sizeof(struct epri)); + } + if (ESHK(mtmp1)) { + if (!ESHK(mtmp2)) neweshk(mtmp2); + (void)memcpy((genericptr_t)ESHK(mtmp2), + (genericptr_t)ESHK(mtmp1), + sizeof(struct eshk)); + } + if (EMIN(mtmp1)) { + if (!EMIN(mtmp2)) newemin(mtmp2); + (void)memcpy((genericptr_t)EMIN(mtmp2), + (genericptr_t)EMIN(mtmp1), + sizeof(struct emin)); + } + if (EDOG(mtmp1)) { + if (!EDOG(mtmp2)) newedog(mtmp2); + (void)memcpy((genericptr_t)EDOG(mtmp2), + (genericptr_t)EDOG(mtmp1), + sizeof(struct edog)); + } + if (has_mcorpsenm(mtmp1)) MCORPSENM(mtmp2) = MCORPSENM(mtmp1); } STATIC_OVL void dealloc_mextra(x) struct mextra *x; { - if (x) { - if (x->mname) free((genericptr_t)x->mname); - if (x->egd) free((genericptr_t)x->egd); - if (x->epri) free((genericptr_t)x->epri); - if (x->eshk) free((genericptr_t)x->eshk); - if (x->emin) free((genericptr_t)x->emin); - if (x->edog) free((genericptr_t)x->edog); - /* [no action needed for x->mcorpsenm] */ - free((genericptr_t)x); - } + if (x) { + if (x->mname) free((genericptr_t)x->mname); + if (x->egd) free((genericptr_t)x->egd); + if (x->epri) free((genericptr_t)x->epri); + if (x->eshk) free((genericptr_t)x->eshk); + if (x->emin) free((genericptr_t)x->emin); + if (x->edog) free((genericptr_t)x->edog); + /* [no action needed for x->mcorpsenm] */ + free((genericptr_t)x); + } } void dealloc_monst(mon) struct monst *mon; { - if (mon->mextra) dealloc_mextra(mon->mextra); - free((genericptr_t)mon); + if (mon->mextra) dealloc_mextra(mon->mextra); + free((genericptr_t)mon); } /* remove effects of mtmp from other data structures */ @@ -1420,21 +1429,21 @@ m_detach(mtmp, mptr) struct monst *mtmp; struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ { - if (mtmp->mleashed) m_unleash(mtmp, FALSE); - /* to prevent an infinite relobj-flooreffects-hmon-killed loop */ - mtmp->mtrapped = 0; - mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */ - relobj(mtmp, 0, FALSE); - remove_monster(mtmp->mx, mtmp->my); - if (emits_light(mptr)) - del_light_source(LS_MONSTER, monst_to_any(mtmp)); - newsym(mtmp->mx,mtmp->my); - unstuck(mtmp); - fill_pit(mtmp->mx, mtmp->my); + if (mtmp->mleashed) m_unleash(mtmp, FALSE); + /* to prevent an infinite relobj-flooreffects-hmon-killed loop */ + mtmp->mtrapped = 0; + mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */ + relobj(mtmp, 0, FALSE); + remove_monster(mtmp->mx, mtmp->my); + if (emits_light(mptr)) + del_light_source(LS_MONSTER, monst_to_any(mtmp)); + newsym(mtmp->mx,mtmp->my); + unstuck(mtmp); + fill_pit(mtmp->mx, mtmp->my); - if(mtmp->isshk) shkgone(mtmp); - if(mtmp->wormno) wormgone(mtmp); - iflags.purge_monsters++; + if(mtmp->isshk) shkgone(mtmp); + if(mtmp->wormno) wormgone(mtmp); + iflags.purge_monsters++; } /* find the worn amulet of life saving which will save a monster */ @@ -1442,181 +1451,181 @@ struct obj * mlifesaver(mon) struct monst *mon; { - if (!nonliving(mon->data) || is_vampshifter(mon)) { - struct obj *otmp = which_armor(mon, W_AMUL); + if (!nonliving(mon->data) || is_vampshifter(mon)) { + struct obj *otmp = which_armor(mon, W_AMUL); - if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING) - return otmp; - } - return (struct obj *)0; + if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING) + return otmp; + } + return (struct obj *)0; } STATIC_OVL void lifesaved_monster(mtmp) struct monst *mtmp; { - boolean surviver; - struct obj *lifesave = mlifesaver(mtmp); - - if (lifesave) { - /* not canseemon; amulets are on the head, so you don't want - * to show this for a long worm with only a tail visible. - * Nor do you check invisibility, because glowing and - * disintegrating amulets are always visible. */ - if (cansee(mtmp->mx, mtmp->my)) { - pline("But wait..."); - pline("%s medallion begins to glow!", - s_suffix(Monnam(mtmp))); - makeknown(AMULET_OF_LIFE_SAVING); - /* amulet is visible, but monster might not be */ - if (canseemon(mtmp)) { - if (attacktype(mtmp->data, AT_EXPL) - || attacktype(mtmp->data, AT_BOOM)) - pline("%s reconstitutes!", Monnam(mtmp)); - else - pline("%s looks much better!", Monnam(mtmp)); - } - pline_The("medallion crumbles to dust!"); - } - m_useup(mtmp, lifesave); - - surviver = !(mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); - mtmp->mcanmove = 1; - mtmp->mfrozen = 0; - if (mtmp->mtame && !mtmp->isminion) { - wary_dog(mtmp, !surviver); - } - if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; - mtmp->mhp = mtmp->mhpmax; - if (surviver) return; - - /* genocided monster can't be life-saved */ - if (cansee(mtmp->mx, mtmp->my)) - pline("Unfortunately, %s is still genocided...", - mon_nam(mtmp)); - } - mtmp->mhp = 0; + boolean surviver; + struct obj *lifesave = mlifesaver(mtmp); + + if (lifesave) { + /* not canseemon; amulets are on the head, so you don't want + * to show this for a long worm with only a tail visible. + * Nor do you check invisibility, because glowing and + * disintegrating amulets are always visible. */ + if (cansee(mtmp->mx, mtmp->my)) { + pline("But wait..."); + pline("%s medallion begins to glow!", + s_suffix(Monnam(mtmp))); + makeknown(AMULET_OF_LIFE_SAVING); + /* amulet is visible, but monster might not be */ + if (canseemon(mtmp)) { + if (attacktype(mtmp->data, AT_EXPL) + || attacktype(mtmp->data, AT_BOOM)) + pline("%s reconstitutes!", Monnam(mtmp)); + else + pline("%s looks much better!", Monnam(mtmp)); + } + pline_The("medallion crumbles to dust!"); + } + m_useup(mtmp, lifesave); + + surviver = !(mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); + mtmp->mcanmove = 1; + mtmp->mfrozen = 0; + if (mtmp->mtame && !mtmp->isminion) { + wary_dog(mtmp, !surviver); + } + if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; + mtmp->mhp = mtmp->mhpmax; + if (surviver) return; + + /* genocided monster can't be life-saved */ + if (cansee(mtmp->mx, mtmp->my)) + pline("Unfortunately, %s is still genocided...", + mon_nam(mtmp)); + } + mtmp->mhp = 0; } void mondead(mtmp) register struct monst *mtmp; { - struct permonst *mptr; - int tmp; - - lifesaved_monster(mtmp); - if (mtmp->mhp > 0) return; - - if (is_vampshifter(mtmp)) { - int mndx = mtmp->cham; - int x = mtmp->mx, y = mtmp->my; - /* this only happens if shapeshifted */ - if (mndx >= LOW_PM && mndx != monsndx(mtmp->data)) { - char buf[BUFSZ]; - boolean in_door = amorphous(mtmp->data) && - closed_door(mtmp->mx,mtmp->my); - Sprintf(buf, - "The %s%s suddenly %s and rises as %%s!", - (nonliving(mtmp->data) || - noncorporeal(mtmp->data) || - amorphous(mtmp->data)) ? "" : "seemingly dead ", - x_monnam(mtmp, ARTICLE_NONE, (char *)0, - SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION | - SUPPRESS_INVISIBLE | SUPPRESS_IT, FALSE), - (nonliving(mtmp->data) || - noncorporeal(mtmp->data) || - amorphous(mtmp->data)) ? - "reconstitutes" : "transforms"); - mtmp->mcanmove = 1; - mtmp->mfrozen = 0; - if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; - mtmp->mhp = mtmp->mhpmax; - /* this can happen if previously a fog cloud */ - if (u.uswallow && (mtmp == u.ustuck)) - expels(mtmp, mtmp->data, FALSE); - if (in_door) { - coord new_xy; - if (enexto(&new_xy, - mtmp->mx, mtmp->my, &mons[mndx])) { - rloc_to(mtmp, new_xy.x, new_xy.y); - } - } - newcham(mtmp, &mons[mndx], FALSE, FALSE); - if (mtmp->data == &mons[mndx]) - mtmp->cham = NON_PM; - else - mtmp->cham = mndx; - if ((!Blind && canseemon(mtmp)) || sensemon(mtmp)) - pline(buf, a_monnam(mtmp)); - newsym(x,y); - return; - } - } - - /* dead vault guard is actually kept at coordinate <0,0> until - his temporary corridor to/from the vault has been removed; - need to do this after life-saving and before m_detach() */ - if (mtmp->isgd && !grddead(mtmp)) return; - - /* Player is thrown from his steed when it dies */ - if (mtmp == u.usteed) - dismount_steed(DISMOUNT_GENERIC); - - mptr = mtmp->data; /* save this for m_detach() */ - /* restore chameleon, lycanthropes to true form at death */ - if (mtmp->cham >= LOW_PM) { - set_mon_data(mtmp, &mons[mtmp->cham], -1); - mtmp->cham = NON_PM; - } - else if (mtmp->data == &mons[PM_WEREJACKAL]) - set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1); - else if (mtmp->data == &mons[PM_WEREWOLF]) - set_mon_data(mtmp, &mons[PM_HUMAN_WEREWOLF], -1); - else if (mtmp->data == &mons[PM_WERERAT]) - set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1); - - /* if MAXMONNO monsters of a given type have died, and it - * can be done, extinguish that monster. - * - * mvitals[].died does double duty as total number of dead monsters - * and as experience factor for the player killing more monsters. - * this means that a dragon dying by other means reduces the - * experience the player gets for killing a dragon directly; this - * is probably not too bad, since the player likely finagled the - * first dead dragon via ring of conflict or pets, and extinguishing - * based on only player kills probably opens more avenues of abuse - * for rings of conflict and such. - */ - tmp = monsndx(mtmp->data); - if (mvitals[tmp].died < 255) mvitals[tmp].died++; - - /* if it's a (possibly polymorphed) quest leader, mark him as dead */ - if (mtmp->m_id == quest_status.leader_m_id) - quest_status.leader_is_dead = TRUE; + struct permonst *mptr; + int tmp; + + lifesaved_monster(mtmp); + if (mtmp->mhp > 0) return; + + if (is_vampshifter(mtmp)) { + int mndx = mtmp->cham; + int x = mtmp->mx, y = mtmp->my; + /* this only happens if shapeshifted */ + if (mndx >= LOW_PM && mndx != monsndx(mtmp->data)) { + char buf[BUFSZ]; + boolean in_door = amorphous(mtmp->data) && + closed_door(mtmp->mx,mtmp->my); + Sprintf(buf, + "The %s%s suddenly %s and rises as %%s!", + (nonliving(mtmp->data) || + noncorporeal(mtmp->data) || + amorphous(mtmp->data)) ? "" : "seemingly dead ", + x_monnam(mtmp, ARTICLE_NONE, (char *)0, + SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION | + SUPPRESS_INVISIBLE | SUPPRESS_IT, FALSE), + (nonliving(mtmp->data) || + noncorporeal(mtmp->data) || + amorphous(mtmp->data)) ? + "reconstitutes" : "transforms"); + mtmp->mcanmove = 1; + mtmp->mfrozen = 0; + if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; + mtmp->mhp = mtmp->mhpmax; + /* this can happen if previously a fog cloud */ + if (u.uswallow && (mtmp == u.ustuck)) + expels(mtmp, mtmp->data, FALSE); + if (in_door) { + coord new_xy; + if (enexto(&new_xy, + mtmp->mx, mtmp->my, &mons[mndx])) { + rloc_to(mtmp, new_xy.x, new_xy.y); + } + } + newcham(mtmp, &mons[mndx], FALSE, FALSE); + if (mtmp->data == &mons[mndx]) + mtmp->cham = NON_PM; + else + mtmp->cham = mndx; + if ((!Blind && canseemon(mtmp)) || sensemon(mtmp)) + pline(buf, a_monnam(mtmp)); + newsym(x,y); + return; + } + } + + /* dead vault guard is actually kept at coordinate <0,0> until + his temporary corridor to/from the vault has been removed; + need to do this after life-saving and before m_detach() */ + if (mtmp->isgd && !grddead(mtmp)) return; + + /* Player is thrown from his steed when it dies */ + if (mtmp == u.usteed) + dismount_steed(DISMOUNT_GENERIC); + + mptr = mtmp->data; /* save this for m_detach() */ + /* restore chameleon, lycanthropes to true form at death */ + if (mtmp->cham >= LOW_PM) { + set_mon_data(mtmp, &mons[mtmp->cham], -1); + mtmp->cham = NON_PM; + } + else if (mtmp->data == &mons[PM_WEREJACKAL]) + set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1); + else if (mtmp->data == &mons[PM_WEREWOLF]) + set_mon_data(mtmp, &mons[PM_HUMAN_WEREWOLF], -1); + else if (mtmp->data == &mons[PM_WERERAT]) + set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1); + + /* if MAXMONNO monsters of a given type have died, and it + * can be done, extinguish that monster. + * + * mvitals[].died does double duty as total number of dead monsters + * and as experience factor for the player killing more monsters. + * this means that a dragon dying by other means reduces the + * experience the player gets for killing a dragon directly; this + * is probably not too bad, since the player likely finagled the + * first dead dragon via ring of conflict or pets, and extinguishing + * based on only player kills probably opens more avenues of abuse + * for rings of conflict and such. + */ + tmp = monsndx(mtmp->data); + if (mvitals[tmp].died < 255) mvitals[tmp].died++; + + /* if it's a (possibly polymorphed) quest leader, mark him as dead */ + if (mtmp->m_id == quest_status.leader_m_id) + quest_status.leader_is_dead = TRUE; #ifdef MAIL - /* if the mail daemon dies, no more mail delivery. -3. */ - if (tmp == PM_MAIL_DAEMON) mvitals[tmp].mvflags |= G_GENOD; + /* if the mail daemon dies, no more mail delivery. -3. */ + if (tmp == PM_MAIL_DAEMON) mvitals[tmp].mvflags |= G_GENOD; #endif - if (mtmp->data->mlet == S_KOP) { - /* Dead Kops may come back. */ - switch(rnd(5)) { - case 1: /* returns near the stairs */ - (void) makemon(mtmp->data,xdnstair,ydnstair,NO_MM_FLAGS); - break; - case 2: /* randomly */ - (void) makemon(mtmp->data,0,0,NO_MM_FLAGS); - break; - default: - break; - } - } - if(mtmp->iswiz) wizdead(); - if(mtmp->data->msound == MS_NEMESIS) nemdead(); - if(glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) - unmap_object(mtmp->mx, mtmp->my); - m_detach(mtmp, mptr); + if (mtmp->data->mlet == S_KOP) { + /* Dead Kops may come back. */ + switch(rnd(5)) { + case 1: /* returns near the stairs */ + (void) makemon(mtmp->data,xdnstair,ydnstair,NO_MM_FLAGS); + break; + case 2: /* randomly */ + (void) makemon(mtmp->data,0,0,NO_MM_FLAGS); + break; + default: + break; + } + } + if(mtmp->iswiz) wizdead(); + if(mtmp->data->msound == MS_NEMESIS) nemdead(); + if(glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) + unmap_object(mtmp->mx, mtmp->my); + m_detach(mtmp, mptr); } /* TRUE if corpse might be dropped, magr may die if mon was swallowed */ @@ -1626,64 +1635,64 @@ struct monst *mon; struct monst *magr; /* killer, if swallowed */ boolean was_swallowed; /* digestion */ { - struct permonst *mdat = mon->data; - int i, tmp; - - if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) { - if (cansee(mon->mx, mon->my) && !was_swallowed) - pline("%s body crumbles into dust.", s_suffix(Monnam(mon))); - return FALSE; - } - - /* Gas spores always explode upon death */ - for(i = 0; i < NATTK; i++) { - if (mdat->mattk[i].aatyp == AT_BOOM) { - if (mdat->mattk[i].damn) - tmp = d((int)mdat->mattk[i].damn, - (int)mdat->mattk[i].damd); - else if(mdat->mattk[i].damd) - tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd); - else tmp = 0; - if (was_swallowed && magr) { - if (magr == &youmonst) { - There("is an explosion in your %s!", - body_part(STOMACH)); - Sprintf(killer.name, "%s explosion", - s_suffix(mdat->mname)); - losehp(Maybe_Half_Phys(tmp), killer.name, KILLED_BY_AN); - } else { - You_hear("an explosion."); - magr->mhp -= tmp; - if (magr->mhp < 1) mondied(magr); - if (magr->mhp < 1) { /* maybe lifesaved */ - if (canspotmon(magr)) - pline("%s rips open!", Monnam(magr)); - } else if (canseemon(magr)) - pline("%s seems to have indigestion.", - Monnam(magr)); - } - - return FALSE; - } - - Sprintf(killer.name, "%s explosion", s_suffix(mdat->mname)); - killer.format = KILLED_BY_AN; - explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE, EXPL_NOXIOUS); - return (FALSE); - } - } - - /* must duplicate this below check in xkilled() since it results in - * creating no objects as well as no corpse - */ - if (LEVEL_SPECIFIC_NOCORPSE(mdat)) - return FALSE; - - if (((bigmonst(mdat) || mdat == &mons[PM_LIZARD]) && !mon->mcloned) || - is_golem(mdat) || is_mplayer(mdat) || is_rider(mdat)) - return TRUE; - tmp = 2 + ((mdat->geno & G_FREQ) < 2) + verysmall(mdat); - return (boolean) !rn2(tmp); + struct permonst *mdat = mon->data; + int i, tmp; + + if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) { + if (cansee(mon->mx, mon->my) && !was_swallowed) + pline("%s body crumbles into dust.", s_suffix(Monnam(mon))); + return FALSE; + } + + /* Gas spores always explode upon death */ + for(i = 0; i < NATTK; i++) { + if (mdat->mattk[i].aatyp == AT_BOOM) { + if (mdat->mattk[i].damn) + tmp = d((int)mdat->mattk[i].damn, + (int)mdat->mattk[i].damd); + else if(mdat->mattk[i].damd) + tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd); + else tmp = 0; + if (was_swallowed && magr) { + if (magr == &youmonst) { + There("is an explosion in your %s!", + body_part(STOMACH)); + Sprintf(killer.name, "%s explosion", + s_suffix(mdat->mname)); + losehp(Maybe_Half_Phys(tmp), killer.name, KILLED_BY_AN); + } else { + You_hear("an explosion."); + magr->mhp -= tmp; + if (magr->mhp < 1) mondied(magr); + if (magr->mhp < 1) { /* maybe lifesaved */ + if (canspotmon(magr)) + pline("%s rips open!", Monnam(magr)); + } else if (canseemon(magr)) + pline("%s seems to have indigestion.", + Monnam(magr)); + } + + return FALSE; + } + + Sprintf(killer.name, "%s explosion", s_suffix(mdat->mname)); + killer.format = KILLED_BY_AN; + explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE, EXPL_NOXIOUS); + return (FALSE); + } + } + + /* must duplicate this below check in xkilled() since it results in + * creating no objects as well as no corpse + */ + if (LEVEL_SPECIFIC_NOCORPSE(mdat)) + return FALSE; + + if (((bigmonst(mdat) || mdat == &mons[PM_LIZARD]) && !mon->mcloned) || + is_golem(mdat) || is_mplayer(mdat) || is_rider(mdat)) + return TRUE; + tmp = 2 + ((mdat->geno & G_FREQ) < 2) + verysmall(mdat); + return (boolean) !rn2(tmp); } /* drop (perhaps) a cadaver and remove monster */ @@ -1691,12 +1700,12 @@ void mondied(mdef) register struct monst *mdef; { - mondead(mdef); - if (mdef->mhp > 0) return; /* lifesaved */ + mondead(mdef); + if (mdef->mhp > 0) return; /* lifesaved */ - if (corpse_chance(mdef, (struct monst *)0, FALSE) && - (accessible(mdef->mx, mdef->my) || is_pool(mdef->mx, mdef->my))) - (void) make_corpse(mdef,CORPSTAT_NONE); + if (corpse_chance(mdef, (struct monst *)0, FALSE) && + (accessible(mdef->mx, mdef->my) || is_pool(mdef->mx, mdef->my))) + (void) make_corpse(mdef,CORPSTAT_NONE); } /* monster disappears, not dies */ @@ -1704,17 +1713,17 @@ void mongone(mdef) register struct monst *mdef; { - mdef->mhp = 0; /* can skip some inventory bookkeeping */ - /* Player is thrown from his steed when it disappears */ - if (mdef == u.usteed) - dismount_steed(DISMOUNT_GENERIC); + mdef->mhp = 0; /* can skip some inventory bookkeeping */ + /* Player is thrown from his steed when it disappears */ + if (mdef == u.usteed) + dismount_steed(DISMOUNT_GENERIC); - /* drop special items like the Amulet so that a dismissed Kop or nurse - can't remove them from the game */ - mdrop_special_objs(mdef); - /* release rest of monster's inventory--it is removed from game */ - discard_minvent(mdef); - m_detach(mdef, mdef->data); + /* drop special items like the Amulet so that a dismissed Kop or nurse + can't remove them from the game */ + mdrop_special_objs(mdef); + /* release rest of monster's inventory--it is removed from game */ + discard_minvent(mdef); + m_detach(mdef, mdef->data); } /* drop a statue or rock and remove monster */ @@ -1722,74 +1731,74 @@ void monstone(mdef) register struct monst *mdef; { - struct obj *otmp, *obj, *oldminvent; - xchar x = mdef->mx, y = mdef->my; - boolean wasinside = FALSE; - - /* we have to make the statue before calling mondead, to be able to - * put inventory in it, and we have to check for lifesaving before - * making the statue.... - */ - lifesaved_monster(mdef); - if (mdef->mhp > 0) return; - - mdef->mtrapped = 0; /* (see m_detach) */ - - if ((int)mdef->data->msize > MZ_TINY || - !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) { - oldminvent = 0; - /* some objects may end up outside the statue */ - while ((obj = mdef->minvent) != 0) { - obj_extract_self(obj); - if (obj->owornmask) - update_mon_intrinsics(mdef, obj, FALSE, TRUE); - obj_no_longer_held(obj); - if (obj->owornmask & W_WEP) - setmnotwielded(mdef,obj); - obj->owornmask = 0L; - if (obj->otyp == BOULDER || + struct obj *otmp, *obj, *oldminvent; + xchar x = mdef->mx, y = mdef->my; + boolean wasinside = FALSE; + + /* we have to make the statue before calling mondead, to be able to + * put inventory in it, and we have to check for lifesaving before + * making the statue.... + */ + lifesaved_monster(mdef); + if (mdef->mhp > 0) return; + + mdef->mtrapped = 0; /* (see m_detach) */ + + if ((int)mdef->data->msize > MZ_TINY || + !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) { + oldminvent = 0; + /* some objects may end up outside the statue */ + while ((obj = mdef->minvent) != 0) { + obj_extract_self(obj); + if (obj->owornmask) + update_mon_intrinsics(mdef, obj, FALSE, TRUE); + obj_no_longer_held(obj); + if (obj->owornmask & W_WEP) + setmnotwielded(mdef,obj); + obj->owornmask = 0L; + if (obj->otyp == BOULDER || #if 0 /* monsters don't carry statues */ (obj->otyp == STATUE && mons[obj->corpsenm].msize >= mdef->data->msize) || #endif - obj_resists(obj, 0, 0)) { - if (flooreffects(obj, x, y, "fall")) continue; - place_object(obj, x, y); - } else { - if (obj->lamplit) end_burn(obj, TRUE); - obj->nobj = oldminvent; - oldminvent = obj; - } - } - /* defer statue creation until after inventory removal - so that saved monster traits won't retain any stale - item-conferred attributes */ - otmp = mkcorpstat(STATUE, mdef, mdef->data, x, y, CORPSTAT_NONE); - if (has_mname(mdef)) otmp = oname(otmp, MNAME(mdef)); - while ((obj = oldminvent) != 0) { - oldminvent = obj->nobj; - (void) add_to_container(otmp, obj); - } - /* Archeologists should not break unique statues */ - if (mdef->data->geno & G_UNIQ) - otmp->spe = 1; - otmp->owt = weight(otmp); - } else - otmp = mksobj_at(ROCK, x, y, TRUE, FALSE); - - stackobj(otmp); - /* mondead() already does this, but we must do it before the newsym */ - if(glyph_is_invisible(levl[x][y].glyph)) - unmap_object(x, y); - if (cansee(x, y)) newsym(x,y); - /* We don't currently trap the hero in the statue in this case but we could */ - if (u.uswallow && u.ustuck == mdef) wasinside = TRUE; - mondead(mdef); - if (wasinside) { - if (is_animal(mdef->data)) - You("%s through an opening in the new %s.", - locomotion(youmonst.data, "jump"), - xname(otmp)); - } + obj_resists(obj, 0, 0)) { + if (flooreffects(obj, x, y, "fall")) continue; + place_object(obj, x, y); + } else { + if (obj->lamplit) end_burn(obj, TRUE); + obj->nobj = oldminvent; + oldminvent = obj; + } + } + /* defer statue creation until after inventory removal + so that saved monster traits won't retain any stale + item-conferred attributes */ + otmp = mkcorpstat(STATUE, mdef, mdef->data, x, y, CORPSTAT_NONE); + if (has_mname(mdef)) otmp = oname(otmp, MNAME(mdef)); + while ((obj = oldminvent) != 0) { + oldminvent = obj->nobj; + (void) add_to_container(otmp, obj); + } + /* Archeologists should not break unique statues */ + if (mdef->data->geno & G_UNIQ) + otmp->spe = 1; + otmp->owt = weight(otmp); + } else + otmp = mksobj_at(ROCK, x, y, TRUE, FALSE); + + stackobj(otmp); + /* mondead() already does this, but we must do it before the newsym */ + if(glyph_is_invisible(levl[x][y].glyph)) + unmap_object(x, y); + if (cansee(x, y)) newsym(x,y); + /* We don't currently trap the hero in the statue in this case but we could */ + if (u.uswallow && u.ustuck == mdef) wasinside = TRUE; + mondead(mdef); + if (wasinside) { + if (is_animal(mdef->data)) + You("%s through an opening in the new %s.", + locomotion(youmonst.data, "jump"), + xname(otmp)); + } } /* another monster has killed the monster mdef */ @@ -1799,51 +1808,51 @@ register struct monst *mdef; const char *fltxt; int how; { - boolean be_sad = FALSE; /* true if unseen pet is killed */ + boolean be_sad = FALSE; /* true if unseen pet is killed */ - if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my)) - && fltxt) - pline("%s is %s%s%s!", Monnam(mdef), - nonliving(mdef->data) ? "destroyed" : "killed", - *fltxt ? " by the " : "", - fltxt - ); - else - be_sad = (mdef->mtame != 0); + if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my)) + && fltxt) + pline("%s is %s%s%s!", Monnam(mdef), + nonliving(mdef->data) ? "destroyed" : "killed", + *fltxt ? " by the " : "", + fltxt + ); + else + be_sad = (mdef->mtame != 0); - /* no corpses if digested or disintegrated */ - if(how == AD_DGST || how == -AD_RBRE) - mondead(mdef); - else - mondied(mdef); + /* no corpses if digested or disintegrated */ + if(how == AD_DGST || how == -AD_RBRE) + mondead(mdef); + else + mondied(mdef); - if (be_sad && mdef->mhp <= 0) - You("have a sad feeling for a moment, then it passes."); + if (be_sad && mdef->mhp <= 0) + You("have a sad feeling for a moment, then it passes."); } void unstuck(mtmp) register struct monst *mtmp; { - if(u.ustuck == mtmp) { - if(u.uswallow){ - u.ux = mtmp->mx; - u.uy = mtmp->my; - u.uswallow = 0; - u.uswldtim = 0; - if (Punished) placebc(); - vision_full_recalc = 1; - docrt(); - } - u.ustuck = 0; - } + if(u.ustuck == mtmp) { + if(u.uswallow){ + u.ux = mtmp->mx; + u.uy = mtmp->my; + u.uswallow = 0; + u.uswldtim = 0; + if (Punished) placebc(); + vision_full_recalc = 1; + docrt(); + } + u.ustuck = 0; + } } void killed(mtmp) register struct monst *mtmp; { - xkilled(mtmp, 1); + xkilled(mtmp, 1); } /* the player has killed the monster mtmp */ @@ -1856,180 +1865,180 @@ struct monst *mtmp; */ int dest; { - int tmp, mndx, x = mtmp->mx, y = mtmp->my; - struct permonst *mdat; - struct obj *otmp; - struct trap *t; - boolean wasinside = u.uswallow && (u.ustuck == mtmp); - boolean burycorpse = FALSE; - - /* KMH, conduct */ - u.uconduct.killer++; - - if (dest & 1) { - const char *verb = nonliving(mtmp->data) ? "destroy" : "kill"; - - if (!wasinside && !canspotmon(mtmp)) - You("%s it!", verb); - else { - You("%s %s!", verb, - !mtmp->mtame ? mon_nam(mtmp) : - x_monnam(mtmp, - (has_mname(mtmp)) ? ARTICLE_NONE : ARTICLE_THE, - "poor", - (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, - FALSE)); - } - } - - if (mtmp->mtrapped && (t = t_at(x, y)) != 0 && - (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { - - if (sobj_at(BOULDER, x, y)) - dest |= 2; /* - * Prevent corpses/treasure being created "on top" - * of the boulder that is about to fall in. This is - * out of order, but cannot be helped unless this - * whole routine is rearranged. - */ - if (m_carrying(mtmp, BOULDER)) - burycorpse = TRUE; - } - - /* your pet knows who just killed it...watch out */ - if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->killed_by_u = 1; - - if (wasinside && thrownobj && thrownobj != uball) { - /* thrown object has killed hero's engulfer; add it to mon's - inventory now so that it will be placed with mon's other - stuff prior to lookhere/autopickup when hero is expelled - below (as a side-effect, this missile has immunity from - being consumed [for this shot/throw only]) */ - mpickobj(mtmp, thrownobj); - /* let throwing code know that missile has been disposed of */ - thrownobj = 0; - } - - /* dispose of monster and make cadaver */ - if(stoned) monstone(mtmp); - else mondead(mtmp); - - if (mtmp->mhp > 0) { /* monster lifesaved */ - /* Cannot put the non-visible lifesaving message in - * lifesaved_monster() since the message appears only when you - * kill it (as opposed to visible lifesaving which always - * appears). - */ - stoned = FALSE; - if (!cansee(x,y)) pline("Maybe not..."); - return; - } - - mdat = mtmp->data; /* note: mondead can change mtmp->data */ - mndx = monsndx(mdat); - - if (stoned) { - stoned = FALSE; - goto cleanup; - } - - if((dest & 2) || LEVEL_SPECIFIC_NOCORPSE(mdat)) - goto cleanup; + int tmp, mndx, x = mtmp->mx, y = mtmp->my; + struct permonst *mdat; + struct obj *otmp; + struct trap *t; + boolean wasinside = u.uswallow && (u.ustuck == mtmp); + boolean burycorpse = FALSE; + + /* KMH, conduct */ + u.uconduct.killer++; + + if (dest & 1) { + const char *verb = nonliving(mtmp->data) ? "destroy" : "kill"; + + if (!wasinside && !canspotmon(mtmp)) + You("%s it!", verb); + else { + You("%s %s!", verb, + !mtmp->mtame ? mon_nam(mtmp) : + x_monnam(mtmp, + (has_mname(mtmp)) ? ARTICLE_NONE : ARTICLE_THE, + "poor", + (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, + FALSE)); + } + } + + if (mtmp->mtrapped && (t = t_at(x, y)) != 0 && + (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { + + if (sobj_at(BOULDER, x, y)) + dest |= 2; /* + * Prevent corpses/treasure being created "on top" + * of the boulder that is about to fall in. This is + * out of order, but cannot be helped unless this + * whole routine is rearranged. + */ + if (m_carrying(mtmp, BOULDER)) + burycorpse = TRUE; + } + + /* your pet knows who just killed it...watch out */ + if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->killed_by_u = 1; + + if (wasinside && thrownobj && thrownobj != uball) { + /* thrown object has killed hero's engulfer; add it to mon's + inventory now so that it will be placed with mon's other + stuff prior to lookhere/autopickup when hero is expelled + below (as a side-effect, this missile has immunity from + being consumed [for this shot/throw only]) */ + mpickobj(mtmp, thrownobj); + /* let throwing code know that missile has been disposed of */ + thrownobj = 0; + } + + /* dispose of monster and make cadaver */ + if(stoned) monstone(mtmp); + else mondead(mtmp); + + if (mtmp->mhp > 0) { /* monster lifesaved */ + /* Cannot put the non-visible lifesaving message in + * lifesaved_monster() since the message appears only when you + * kill it (as opposed to visible lifesaving which always + * appears). + */ + stoned = FALSE; + if (!cansee(x,y)) pline("Maybe not..."); + return; + } + + mdat = mtmp->data; /* note: mondead can change mtmp->data */ + mndx = monsndx(mdat); + + if (stoned) { + stoned = FALSE; + goto cleanup; + } + + if((dest & 2) || LEVEL_SPECIFIC_NOCORPSE(mdat)) + goto cleanup; #ifdef MAIL - if(mdat == &mons[PM_MAIL_DAEMON]) { - stackobj(mksobj_at(SCR_MAIL, x, y, FALSE, FALSE)); - } + if(mdat == &mons[PM_MAIL_DAEMON]) { + stackobj(mksobj_at(SCR_MAIL, x, y, FALSE, FALSE)); + } #endif - if (accessible(x, y) || is_pool(x, y)) { - struct obj *cadaver; - int otyp; - - /* illogical but traditional "treasure drop" */ - if (!rn2(6) && !(mvitals[mndx].mvflags & G_NOCORPSE) - /* no extra item from swallower or steed */ - && (x != u.ux || y != u.uy) - /* no extra item from kops--too easy to abuse */ - && mdat->mlet != S_KOP + if (accessible(x, y) || is_pool(x, y)) { + struct obj *cadaver; + int otyp; + + /* illogical but traditional "treasure drop" */ + if (!rn2(6) && !(mvitals[mndx].mvflags & G_NOCORPSE) + /* no extra item from swallower or steed */ + && (x != u.ux || y != u.uy) + /* no extra item from kops--too easy to abuse */ + && mdat->mlet != S_KOP /* no items from cloned monsters */ - && !mtmp->mcloned) { - otmp = mkobj(RANDOM_CLASS, TRUE); - /* don't create large objects from small monsters */ - otyp = otmp->otyp; - if (mdat->msize < MZ_HUMAN && otyp != FIGURINE && - /* oc_big is also oc_bimanual and oc_bulky */ - (otmp->owt > 30 || objects[otyp].oc_big)) { - delobj(otmp); - } else if (!flooreffects(otmp, x, y, - (dest & 1) ? "fall" : "")) { - place_object(otmp, x, y); - stackobj(otmp); - } - } - /* corpse--none if hero was inside the monster */ - if (!wasinside && corpse_chance(mtmp, (struct monst *)0, FALSE)) { - cadaver = make_corpse(mtmp, burycorpse ? - CORPSTAT_BURIED : CORPSTAT_NONE); - if (burycorpse && cadaver && cansee(x,y) && !mtmp->minvis && - cadaver->where == OBJ_BURIED && (dest & 1)) { - pline("%s corpse ends up buried.", s_suffix(Monnam(mtmp))); - } - } - } - if (wasinside) spoteffects(TRUE); /* poor man's expels() */ - /* monster is gone, corpse or other object might now be visible */ - newsym(x, y); + && !mtmp->mcloned) { + otmp = mkobj(RANDOM_CLASS, TRUE); + /* don't create large objects from small monsters */ + otyp = otmp->otyp; + if (mdat->msize < MZ_HUMAN && otyp != FIGURINE && + /* oc_big is also oc_bimanual and oc_bulky */ + (otmp->owt > 30 || objects[otyp].oc_big)) { + delobj(otmp); + } else if (!flooreffects(otmp, x, y, + (dest & 1) ? "fall" : "")) { + place_object(otmp, x, y); + stackobj(otmp); + } + } + /* corpse--none if hero was inside the monster */ + if (!wasinside && corpse_chance(mtmp, (struct monst *)0, FALSE)) { + cadaver = make_corpse(mtmp, burycorpse ? + CORPSTAT_BURIED : CORPSTAT_NONE); + if (burycorpse && cadaver && cansee(x,y) && !mtmp->minvis && + cadaver->where == OBJ_BURIED && (dest & 1)) { + pline("%s corpse ends up buried.", s_suffix(Monnam(mtmp))); + } + } + } + if (wasinside) spoteffects(TRUE); /* poor man's expels() */ + /* monster is gone, corpse or other object might now be visible */ + newsym(x, y); cleanup: - /* punish bad behaviour */ - if(is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) && - (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) && - u.ualign.type != A_CHAOTIC) { - HTelepat &= ~INTRINSIC; - change_luck(-2); - You("murderer!"); - if (Blind && !Blind_telepat) - see_monsters(); /* Can't sense monsters any more. */ - } - if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1); - if (is_unicorn(mdat) && - sgn(u.ualign.type) == sgn(mdat->maligntyp)) { - change_luck(-5); - You_feel("guilty..."); - } - - /* give experience points */ - tmp = experience(mtmp, (int)mvitals[mndx].died); - more_experienced(tmp, 0); - newexplevel(); /* will decide if you go up */ - - /* adjust alignment points */ - if (mtmp->m_id == quest_status.leader_m_id) { /* REAL BAD! */ - adjalign(-(u.ualign.record+(int)ALIGNLIM/2)); - pline("That was %sa bad idea...", - u.uevent.qcompleted ? "probably " : ""); - } else if (mdat->msound == MS_NEMESIS) /* Real good! */ - adjalign((int)(ALIGNLIM/4)); - else if (mdat->msound == MS_GUARDIAN) { /* Bad */ - adjalign(-(int)(ALIGNLIM/8)); - if (!Hallucination) pline("That was probably a bad idea..."); - else pline("Whoopsie-daisy!"); - }else if (mtmp->ispriest) { - adjalign((p_coaligned(mtmp)) ? -2 : 2); - /* cancel divine protection for killing your priest */ - if (p_coaligned(mtmp)) u.ublessed = 0; - if (mdat->maligntyp == A_NONE) - adjalign((int)(ALIGNLIM / 4)); /* BIG bonus */ - } else if (mtmp->mtame) { - adjalign(-15); /* bad!! */ - /* your god is mighty displeased... */ - if (!Hallucination) You_hear("the rumble of distant thunder..."); - else You_hear("the studio audience applaud!"); - } else if (mtmp->mpeaceful) - adjalign(-5); - - /* malign was already adjusted for u.ualign.type and randomization */ - adjalign(mtmp->malign); + /* punish bad behaviour */ + if(is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) && + (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) && + u.ualign.type != A_CHAOTIC) { + HTelepat &= ~INTRINSIC; + change_luck(-2); + You("murderer!"); + if (Blind && !Blind_telepat) + see_monsters(); /* Can't sense monsters any more. */ + } + if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1); + if (is_unicorn(mdat) && + sgn(u.ualign.type) == sgn(mdat->maligntyp)) { + change_luck(-5); + You_feel("guilty..."); + } + + /* give experience points */ + tmp = experience(mtmp, (int)mvitals[mndx].died); + more_experienced(tmp, 0); + newexplevel(); /* will decide if you go up */ + + /* adjust alignment points */ + if (mtmp->m_id == quest_status.leader_m_id) { /* REAL BAD! */ + adjalign(-(u.ualign.record+(int)ALIGNLIM/2)); + pline("That was %sa bad idea...", + u.uevent.qcompleted ? "probably " : ""); + } else if (mdat->msound == MS_NEMESIS) /* Real good! */ + adjalign((int)(ALIGNLIM/4)); + else if (mdat->msound == MS_GUARDIAN) { /* Bad */ + adjalign(-(int)(ALIGNLIM/8)); + if (!Hallucination) pline("That was probably a bad idea..."); + else pline("Whoopsie-daisy!"); + }else if (mtmp->ispriest) { + adjalign((p_coaligned(mtmp)) ? -2 : 2); + /* cancel divine protection for killing your priest */ + if (p_coaligned(mtmp)) u.ublessed = 0; + if (mdat->maligntyp == A_NONE) + adjalign((int)(ALIGNLIM / 4)); /* BIG bonus */ + } else if (mtmp->mtame) { + adjalign(-15); /* bad!! */ + /* your god is mighty displeased... */ + if (!Hallucination) You_hear("the rumble of distant thunder..."); + else You_hear("the studio audience applaud!"); + } else if (mtmp->mpeaceful) + adjalign(-5); + + /* malign was already adjusted for u.ualign.type and randomization */ + adjalign(mtmp->malign); } /* changes the monster into a stone monster of the same type */ @@ -2039,44 +2048,44 @@ mon_to_stone(mtmp) register struct monst *mtmp; { if(mtmp->data->mlet == S_GOLEM) { - /* it's a golem, and not a stone golem */ - if(canseemon(mtmp)) - pline("%s solidifies...", Monnam(mtmp)); - if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) { - if(canseemon(mtmp)) - pline("Now it's %s.", an(mtmp->data->mname)); - } else { - if(canseemon(mtmp)) - pline("... and returns to normal."); - } + /* it's a golem, and not a stone golem */ + if(canseemon(mtmp)) + pline("%s solidifies...", Monnam(mtmp)); + if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) { + if(canseemon(mtmp)) + pline("Now it's %s.", an(mtmp->data->mname)); + } else { + if(canseemon(mtmp)) + pline("... and returns to normal."); + } } else - impossible("Can't polystone %s!", a_monnam(mtmp)); + impossible("Can't polystone %s!", a_monnam(mtmp)); } /* might place monst on far side of a wall or boulder */ void mnexto(mtmp) /* Make monster mtmp next to you (if possible) */ - struct monst *mtmp; + struct monst *mtmp; { - coord mm; - boolean couldspot = canspotmon(mtmp); + coord mm; + boolean couldspot = canspotmon(mtmp); - if (mtmp == u.usteed) { - /* Keep your steed in sync with you instead */ - mtmp->mx = u.ux; - mtmp->my = u.uy; - return; - } + if (mtmp == u.usteed) { + /* Keep your steed in sync with you instead */ + mtmp->mx = u.ux; + mtmp->my = u.uy; + return; + } - if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return; - rloc_to(mtmp, mm.x, mm.y); - if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) { - mtmp->mstrategy &= ~STRAT_APPEARMSG; /* one chance only */ - if (!couldspot && canspotmon(mtmp)) - pline("%s suddenly %s!", Amonnam(mtmp), - !Blind ? "appears" : "arrives"); - } - return; + if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return; + rloc_to(mtmp, mm.x, mm.y); + if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) { + mtmp->mstrategy &= ~STRAT_APPEARMSG; /* one chance only */ + if (!couldspot && canspotmon(mtmp)) + pline("%s suddenly %s!", Amonnam(mtmp), + !Blind ? "appears" : "arrives"); + } + return; } /* like mnexto() but requires destination to be directly accessible */ @@ -2084,20 +2093,20 @@ void maybe_mnexto(mtmp) struct monst *mtmp; { - coord mm; - struct permonst *ptr = mtmp->data; - boolean diagok = !NODIAG(ptr - mons); - int tryct = 20; + coord mm; + struct permonst *ptr = mtmp->data; + boolean diagok = !NODIAG(ptr - mons); + int tryct = 20; - do { - if (!enexto(&mm, u.ux, u.uy, ptr)) return; - if (couldsee(mm.x, mm.y) && - /* don't move grid bugs diagonally */ - (diagok || mm.x == mtmp->mx || mm.y == mtmp->my)) { - rloc_to(mtmp, mm.x, mm.y); - return; - } - } while (--tryct > 0); + do { + if (!enexto(&mm, u.ux, u.uy, ptr)) return; + if (couldsee(mm.x, mm.y) && + /* don't move grid bugs diagonally */ + (diagok || mm.x == mtmp->mx || mm.y == mtmp->my)) { + rloc_to(mtmp, mm.x, mm.y); + return; + } + } while (--tryct > 0); } /* mnearto() @@ -2112,41 +2121,41 @@ register struct monst *mtmp; xchar x, y; boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */ { - struct monst *othermon = (struct monst *)0; - xchar newx, newy; - coord mm; + struct monst *othermon = (struct monst *)0; + xchar newx, newy; + coord mm; - if ((mtmp->mx == x) && (mtmp->my == y)) return(FALSE); + if ((mtmp->mx == x) && (mtmp->my == y)) return(FALSE); - if (move_other && (othermon = m_at(x, y))) { - if (othermon->wormno) - remove_worm(othermon); - else - remove_monster(x, y); - } + if (move_other && (othermon = m_at(x, y))) { + if (othermon->wormno) + remove_worm(othermon); + else + remove_monster(x, y); + } - newx = x; - newy = y; + newx = x; + newy = y; - if (!goodpos(newx, newy, mtmp, 0)) { - /* actually we have real problems if enexto ever fails. - * migrating_mons that need to be placed will cause - * no end of trouble. - */ - if (!enexto(&mm, newx, newy, mtmp->data)) return(FALSE); - newx = mm.x; newy = mm.y; - } + if (!goodpos(newx, newy, mtmp, 0)) { + /* actually we have real problems if enexto ever fails. + * migrating_mons that need to be placed will cause + * no end of trouble. + */ + if (!enexto(&mm, newx, newy, mtmp->data)) return(FALSE); + newx = mm.x; newy = mm.y; + } - rloc_to(mtmp, newx, newy); + rloc_to(mtmp, newx, newy); - if (move_other && othermon) { - othermon->mx = othermon->my = 0; - (void) mnearto(othermon, x, y, FALSE); - if ((othermon->mx != x) || (othermon->my != y)) - return(TRUE); - } + if (move_other && othermon) { + othermon->mx = othermon->my = 0; + (void) mnearto(othermon, x, y, FALSE); + if ((othermon->mx != x) || (othermon->my != y)) + return(TRUE); + } - return(FALSE); + return(FALSE); } /* monster responds to player action; not the same as a passive attack */ @@ -2156,26 +2165,26 @@ m_respond(mtmp) register struct monst *mtmp; { if(mtmp->data->msound == MS_SHRIEK) { - if(!Deaf) { - pline("%s shrieks.", Monnam(mtmp)); - stop_occupation(); - } - if (!rn2(10)) { - if (!rn2(13)) - (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS); - else - (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS); - - } - aggravate(); + if(!Deaf) { + pline("%s shrieks.", Monnam(mtmp)); + stop_occupation(); + } + if (!rn2(10)) { + if (!rn2(13)) + (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS); + else + (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS); + + } + aggravate(); } if(mtmp->data == &mons[PM_MEDUSA]) { - register int i; - for(i = 0; i < NATTK; i++) - if(mtmp->data->mattk[i].aatyp == AT_GAZE) { - (void) gazemu(mtmp, &mtmp->data->mattk[i]); - break; - } + register int i; + for(i = 0; i < NATTK; i++) + if(mtmp->data->mattk[i].aatyp == AT_GAZE) { + (void) gazemu(mtmp, &mtmp->data->mattk[i]); + break; + } } } @@ -2183,75 +2192,75 @@ void setmangry(mtmp) register struct monst *mtmp; { - mtmp->mstrategy &= ~STRAT_WAITMASK; - if(!mtmp->mpeaceful) return; - if(mtmp->mtame) return; - mtmp->mpeaceful = 0; - if(mtmp->ispriest) { - if(p_coaligned(mtmp)) adjalign(-5); /* very bad */ - else adjalign(2); - } else - adjalign(-1); /* attacking peaceful monsters is bad */ - if (couldsee(mtmp->mx, mtmp->my)) { - if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd) - pline("%s gets angry!", Monnam(mtmp)); - else if (flags.verbose && !Deaf) growl(mtmp); - } - - /* attacking your own quest leader will anger his or her guardians */ - if (!context.mon_moving && /* should always be the case here */ - mtmp->data == &mons[quest_info(MS_LEADER)]) { - struct monst *mon; - struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)]; - int got_mad = 0; - - /* guardians will sense this attack even if they can't see it */ - for (mon = fmon; mon; mon = mon->nmon) { - if (DEADMONSTER(mon)) continue; - if (mon->data == q_guardian && mon->mpeaceful) { - mon->mpeaceful = 0; - if (canseemon(mon)) ++got_mad; - } - } - if (got_mad && !Hallucination) - pline_The("%s appear%s to be angry too...", - got_mad == 1 ? q_guardian->mname : - makeplural(q_guardian->mname), - got_mad == 1 ? "s" : ""); - } + mtmp->mstrategy &= ~STRAT_WAITMASK; + if(!mtmp->mpeaceful) return; + if(mtmp->mtame) return; + mtmp->mpeaceful = 0; + if(mtmp->ispriest) { + if(p_coaligned(mtmp)) adjalign(-5); /* very bad */ + else adjalign(2); + } else + adjalign(-1); /* attacking peaceful monsters is bad */ + if (couldsee(mtmp->mx, mtmp->my)) { + if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd) + pline("%s gets angry!", Monnam(mtmp)); + else if (flags.verbose && !Deaf) growl(mtmp); + } + + /* attacking your own quest leader will anger his or her guardians */ + if (!context.mon_moving && /* should always be the case here */ + mtmp->data == &mons[quest_info(MS_LEADER)]) { + struct monst *mon; + struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)]; + int got_mad = 0; + + /* guardians will sense this attack even if they can't see it */ + for (mon = fmon; mon; mon = mon->nmon) { + if (DEADMONSTER(mon)) continue; + if (mon->data == q_guardian && mon->mpeaceful) { + mon->mpeaceful = 0; + if (canseemon(mon)) ++got_mad; + } + } + if (got_mad && !Hallucination) + pline_The("%s appear%s to be angry too...", + got_mad == 1 ? q_guardian->mname : + makeplural(q_guardian->mname), + got_mad == 1 ? "s" : ""); + } } void wakeup(mtmp) register struct monst *mtmp; { - mtmp->msleeping = 0; - finish_meating(mtmp); - setmangry(mtmp); - if (mtmp->m_ap_type) { - seemimic(mtmp); - } else if (context.forcefight && !context.mon_moving && - mtmp->mundetected) { - mtmp->mundetected = 0; - newsym(mtmp->mx, mtmp->my); - } + mtmp->msleeping = 0; + finish_meating(mtmp); + setmangry(mtmp); + if (mtmp->m_ap_type) { + seemimic(mtmp); + } else if (context.forcefight && !context.mon_moving && + mtmp->mundetected) { + mtmp->mundetected = 0; + newsym(mtmp->mx, mtmp->my); + } } /* Wake up nearby monsters without angering them. */ void wake_nearby() { - register struct monst *mtmp; + register struct monst *mtmp; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - if (distu(mtmp->mx,mtmp->my) < u.ulevel * 20) { - mtmp->msleeping = 0; - mtmp->mstrategy &= ~STRAT_WAITMASK; - if (mtmp->mtame && !mtmp->isminion) - EDOG(mtmp)->whistletime = moves; - } - } + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (distu(mtmp->mx,mtmp->my) < u.ulevel * 20) { + mtmp->msleeping = 0; + mtmp->mstrategy &= ~STRAT_WAITMASK; + if (mtmp->mtame && !mtmp->isminion) + EDOG(mtmp)->whistletime = moves; + } + } } /* Wake up monsters near some particular location. */ @@ -2259,15 +2268,15 @@ void wake_nearto(x, y, distance) register int x, y, distance; { - register struct monst *mtmp; + register struct monst *mtmp; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - if (distance == 0 || dist2(mtmp->mx, mtmp->my, x, y) < distance) { - mtmp->msleeping = 0; - mtmp->mstrategy &= ~STRAT_WAITMASK; - } - } + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (distance == 0 || dist2(mtmp->mx, mtmp->my, x, y) < distance) { + mtmp->msleeping = 0; + mtmp->mstrategy &= ~STRAT_WAITMASK; + } + } } /* NOTE: we must check for mimicry before calling this routine */ @@ -2275,67 +2284,67 @@ void seemimic(mtmp) register struct monst *mtmp; { - unsigned old_app = mtmp->mappearance; - uchar old_ap_type = mtmp->m_ap_type; + unsigned old_app = mtmp->mappearance; + uchar old_ap_type = mtmp->m_ap_type; - if (has_mcorpsenm(mtmp)) freemcorpsenm(mtmp); + if (has_mcorpsenm(mtmp)) freemcorpsenm(mtmp); - mtmp->m_ap_type = M_AP_NOTHING; - mtmp->mappearance = 0; + mtmp->m_ap_type = M_AP_NOTHING; + mtmp->mappearance = 0; - /* - * Discovered mimics don't block light. - */ - if (((old_ap_type == M_AP_FURNITURE && - (old_app == S_hcdoor || old_app == S_vcdoor)) || - (old_ap_type == M_AP_OBJECT && old_app == BOULDER)) && - !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my])) - unblock_point(mtmp->mx, mtmp->my); + /* + * Discovered mimics don't block light. + */ + if (((old_ap_type == M_AP_FURNITURE && + (old_app == S_hcdoor || old_app == S_vcdoor)) || + (old_ap_type == M_AP_OBJECT && old_app == BOULDER)) && + !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my])) + unblock_point(mtmp->mx, mtmp->my); - newsym(mtmp->mx,mtmp->my); + newsym(mtmp->mx,mtmp->my); } /* force all chameleons to become normal */ void rescham() { - register struct monst *mtmp; - int mcham; - - for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - mcham = (int) mtmp->cham; - if (mcham >= LOW_PM) { - (void) newcham(mtmp, &mons[mcham], - FALSE, FALSE); - mtmp->cham = NON_PM; - } - if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN) - new_were(mtmp); - if(mtmp->m_ap_type && cansee(mtmp->mx, mtmp->my)) { - seemimic(mtmp); - /* we pretend that the mimic doesn't */ - /* know that it has been unmasked. */ - mtmp->msleeping = 1; - } - } + register struct monst *mtmp; + int mcham; + + for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + mcham = (int) mtmp->cham; + if (mcham >= LOW_PM) { + (void) newcham(mtmp, &mons[mcham], + FALSE, FALSE); + mtmp->cham = NON_PM; + } + if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN) + new_were(mtmp); + if(mtmp->m_ap_type && cansee(mtmp->mx, mtmp->my)) { + seemimic(mtmp); + /* we pretend that the mimic doesn't */ + /* know that it has been unmasked. */ + mtmp->msleeping = 1; + } + } } /* Let the chameleons change again -dgk */ void restartcham() { - register struct monst *mtmp; + register struct monst *mtmp; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - mtmp->cham = pm_to_cham(monsndx(mtmp->data)); - if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && - cansee(mtmp->mx, mtmp->my)) { - set_mimic_sym(mtmp); - newsym(mtmp->mx,mtmp->my); - } - } + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + mtmp->cham = pm_to_cham(monsndx(mtmp->data)); + if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && + cansee(mtmp->mx, mtmp->my)) { + set_mimic_sym(mtmp); + newsym(mtmp->mx,mtmp->my); + } + } } /* called when restoring a monster from a saved level; protection @@ -2345,19 +2354,19 @@ void restore_cham(mon) struct monst *mon; { - int mcham; - - if (Protection_from_shape_changers) { - mcham = (int) mon->cham; - if (mcham >= LOW_PM) { - mon->cham = NON_PM; - (void) newcham(mon, &mons[mcham], FALSE, FALSE); - } else if (is_were(mon->data) && !is_human(mon->data)) { - new_were(mon); - } - } else if (mon->cham == NON_PM) { - mon->cham = pm_to_cham(monsndx(mon->data)); - } + int mcham; + + if (Protection_from_shape_changers) { + mcham = (int) mon->cham; + if (mcham >= LOW_PM) { + mon->cham = NON_PM; + (void) newcham(mon, &mons[mcham], FALSE, FALSE); + } else if (is_were(mon->data) && !is_human(mon->data)) { + new_were(mon); + } + } else if (mon->cham == NON_PM) { + mon->cham = pm_to_cham(monsndx(mon->data)); + } } /* unwatched hiders may hide again; if so, a 1 is returned. */ @@ -2365,26 +2374,26 @@ STATIC_OVL boolean restrap(mtmp) register struct monst *mtmp; { - struct trap *t; + struct trap *t; - if (mtmp->mcan || mtmp->m_ap_type || - cansee(mtmp->mx, mtmp->my) || rn2(3) || (mtmp == u.ustuck) || - /* can't hide while trapped except in pits */ - (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0 && - !(t->ttyp == PIT || t->ttyp == SPIKED_PIT)) || - (sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2)) - return(FALSE); + if (mtmp->mcan || mtmp->m_ap_type || + cansee(mtmp->mx, mtmp->my) || rn2(3) || (mtmp == u.ustuck) || + /* can't hide while trapped except in pits */ + (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0 && + !(t->ttyp == PIT || t->ttyp == SPIKED_PIT)) || + (sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2)) + return(FALSE); - if(mtmp->data->mlet == S_MIMIC) { - set_mimic_sym(mtmp); - return(TRUE); - } else - if(levl[mtmp->mx][mtmp->my].typ == ROOM) { - mtmp->mundetected = 1; - return(TRUE); - } + if(mtmp->data->mlet == S_MIMIC) { + set_mimic_sym(mtmp); + return(TRUE); + } else + if(levl[mtmp->mx][mtmp->my].typ == ROOM) { + mtmp->mundetected = 1; + return(TRUE); + } - return(FALSE); + return(FALSE); } /* monster/hero tries to hide under something at the current location */ @@ -2392,33 +2401,33 @@ boolean hideunder(mtmp) struct monst *mtmp; { - struct trap *t; - boolean undetected = FALSE, - is_u = (mtmp == &youmonst); - xchar x = is_u ? u.ux : mtmp->mx, - y = is_u ? u.uy : mtmp->my; - - if (mtmp == u.ustuck) { - ; /* can't hide if holding you or held by you */ - } else if (is_u ? (u.utrap && u.utraptype != TT_PIT) : - (mtmp->mtrapped && (t = t_at(x, y)) != 0 && - !(t->ttyp == PIT || t->ttyp == SPIKED_PIT))) { - ; /* can't hide while stuck in a non-pit trap */ - } else if (mtmp->data->mlet == S_EEL) { - undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz)); - } else if (hides_under(mtmp->data) && OBJ_AT(x, y)) { - struct obj *otmp = level.objects[x][y]; - - /* most monsters won't hide under cockatrice corpse */ - if (otmp->nexthere || otmp->otyp != CORPSE || - (mtmp == &youmonst ? Stone_resistance : resists_ston(mtmp)) || - !touch_petrifies(&mons[otmp->corpsenm])) - undetected = TRUE; - } - - if (is_u) u.uundetected = undetected; - else mtmp->mundetected = undetected; - return undetected; + struct trap *t; + boolean undetected = FALSE, + is_u = (mtmp == &youmonst); + xchar x = is_u ? u.ux : mtmp->mx, + y = is_u ? u.uy : mtmp->my; + + if (mtmp == u.ustuck) { + ; /* can't hide if holding you or held by you */ + } else if (is_u ? (u.utrap && u.utraptype != TT_PIT) : + (mtmp->mtrapped && (t = t_at(x, y)) != 0 && + !(t->ttyp == PIT || t->ttyp == SPIKED_PIT))) { + ; /* can't hide while stuck in a non-pit trap */ + } else if (mtmp->data->mlet == S_EEL) { + undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz)); + } else if (hides_under(mtmp->data) && OBJ_AT(x, y)) { + struct obj *otmp = level.objects[x][y]; + + /* most monsters won't hide under cockatrice corpse */ + if (otmp->nexthere || otmp->otyp != CORPSE || + (mtmp == &youmonst ? Stone_resistance : resists_ston(mtmp)) || + !touch_petrifies(&mons[otmp->corpsenm])) + undetected = TRUE; + } + + if (is_u) u.uundetected = undetected; + else mtmp->mundetected = undetected; + return undetected; } /* called when returning to a previously visited level */ @@ -2429,17 +2438,17 @@ struct monst *mon; boolean hider_under = hides_under(mon->data) || mon->data->mlet == S_EEL; if ((is_hider(mon->data) || hider_under) && - !(mon->mundetected || mon->m_ap_type)) { - xchar x = mon->mx, y = mon->my; - char save_viz = viz_array[y][x]; - - /* override vision, forcing hero to be unable to see monster's spot */ - viz_array[y][x] &= ~(IN_SIGHT | COULD_SEE); - if (is_hider(mon->data)) (void)restrap(mon); - /* try again if mimic missed its 1/3 chance to hide */ - if (mon->data->mlet == S_MIMIC && !mon->m_ap_type) (void)restrap(mon); - if (hider_under) (void)hideunder(mon); - viz_array[y][x] = save_viz; + !(mon->mundetected || mon->m_ap_type)) { + xchar x = mon->mx, y = mon->my; + char save_viz = viz_array[y][x]; + + /* override vision, forcing hero to be unable to see monster's spot */ + viz_array[y][x] &= ~(IN_SIGHT | COULD_SEE); + if (is_hider(mon->data)) (void)restrap(mon); + /* try again if mimic missed its 1/3 chance to hide */ + if (mon->data->mlet == S_MIMIC && !mon->m_ap_type) (void)restrap(mon); + if (hider_under) (void)hideunder(mon); + viz_array[y][x] = save_viz; } } @@ -2450,33 +2459,33 @@ void mon_animal_list(construct) boolean construct; { - if (construct) { - short animal_temp[SPECIAL_PM]; - int i, n; + if (construct) { + short animal_temp[SPECIAL_PM]; + int i, n; - /* if (animal_list) impossible("animal_list already exists"); */ + /* if (animal_list) impossible("animal_list already exists"); */ - for (n = 0, i = LOW_PM; i < SPECIAL_PM; i++) - if (is_animal(&mons[i])) animal_temp[n++] = i; - /* if (n == 0) animal_temp[n++] = NON_PM; */ + for (n = 0, i = LOW_PM; i < SPECIAL_PM; i++) + if (is_animal(&mons[i])) animal_temp[n++] = i; + /* if (n == 0) animal_temp[n++] = NON_PM; */ - animal_list = (short *)alloc(n * sizeof *animal_list); - (void) memcpy((genericptr_t)animal_list, - (genericptr_t)animal_temp, - n * sizeof *animal_list); - animal_list_count = n; - } else { /* release */ - if (animal_list) free((genericptr_t)animal_list), animal_list = 0; - animal_list_count = 0; - } + animal_list = (short *)alloc(n * sizeof *animal_list); + (void) memcpy((genericptr_t)animal_list, + (genericptr_t)animal_temp, + n * sizeof *animal_list); + animal_list_count = n; + } else { /* release */ + if (animal_list) free((genericptr_t)animal_list), animal_list = 0; + animal_list_count = 0; + } } STATIC_OVL int pick_animal() { - if (!animal_list) mon_animal_list(TRUE); + if (!animal_list) mon_animal_list(TRUE); - return animal_list[rn2(animal_list_count)]; + return animal_list[rn2(animal_list_count)]; } void @@ -2484,55 +2493,55 @@ decide_to_shapeshift(mon, shiftflags) struct monst *mon; int shiftflags; { - struct permonst *ptr; - unsigned was_female = mon->female; - boolean msg = FALSE; + struct permonst *ptr; + unsigned was_female = mon->female; + boolean msg = FALSE; - if ((shiftflags & SHIFT_MSG) || - ((shiftflags & SHIFT_SEENMSG) && sensemon(mon))) msg = TRUE; + if ((shiftflags & SHIFT_MSG) || + ((shiftflags & SHIFT_SEENMSG) && sensemon(mon))) msg = TRUE; - if (is_vampshifter(mon)) { - /* The vampire has to be in good health (mhp) to maintain - * its shifted form. + if (is_vampshifter(mon)) { + /* The vampire has to be in good health (mhp) to maintain + * its shifted form. * - * If we're shifted and getting low on hp, maybe shift back. - * If we're not already shifted and in good health, maybe shift. - */ - if ((mon->mhp <= mon->mhpmax / 6) && - rn2(4) && (mon->cham >= LOW_PM)) - (void) newcham(mon, &mons[mon->cham], FALSE, msg); - } else if (mon->data->mlet == S_VAMPIRE && mon->cham == NON_PM && - !rn2(6) && (mon->mhp > mon->mhpmax - ((mon->mhpmax / 10) + 1))) { - (void) newcham(mon, (struct permonst *)0, FALSE, msg); - } - /* override the 10% chance for sex change */ - ptr = mon->data; - if (!is_male(ptr) && !is_female(ptr) && !is_neuter(ptr)) - mon->female = was_female; + * If we're shifted and getting low on hp, maybe shift back. + * If we're not already shifted and in good health, maybe shift. + */ + if ((mon->mhp <= mon->mhpmax / 6) && + rn2(4) && (mon->cham >= LOW_PM)) + (void) newcham(mon, &mons[mon->cham], FALSE, msg); + } else if (mon->data->mlet == S_VAMPIRE && mon->cham == NON_PM && + !rn2(6) && (mon->mhp > mon->mhpmax - ((mon->mhpmax / 10) + 1))) { + (void) newcham(mon, (struct permonst *)0, FALSE, msg); + } + /* override the 10% chance for sex change */ + ptr = mon->data; + if (!is_male(ptr) && !is_female(ptr) && !is_neuter(ptr)) + mon->female = was_female; } STATIC_OVL int pickvampshape(mon) struct monst *mon; { - int mndx = mon->cham; - - switch (mndx) { - case PM_VLAD_THE_IMPALER: - /* ensure Vlad can keep carrying the Candelabrum */ - if (mon_has_special(mon)) break; /* leave mndx as is */ - /*FALLTHRU*/ - case PM_VAMPIRE_LORD: /* vampire lord or Vlad can become wolf */ - if (!rn2(10)) { - mndx = PM_WOLF; - break; - } - /*FALLTHRU*/ - case PM_VAMPIRE: /* any vampire can become fog or bat */ - mndx = !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; - break; - } - return mndx; + int mndx = mon->cham; + + switch (mndx) { + case PM_VLAD_THE_IMPALER: + /* ensure Vlad can keep carrying the Candelabrum */ + if (mon_has_special(mon)) break; /* leave mndx as is */ + /*FALLTHRU*/ + case PM_VAMPIRE_LORD: /* vampire lord or Vlad can become wolf */ + if (!rn2(10)) { + mndx = PM_WOLF; + break; + } + /*FALLTHRU*/ + case PM_VAMPIRE: /* any vampire can become fog or bat */ + mndx = !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; + break; + } + return mndx; } /* nonshapechangers who warrant special polymorph handling */ @@ -2540,8 +2549,8 @@ STATIC_OVL boolean isspecmon(mon) struct monst *mon; { - return (mon->isshk || mon->ispriest || mon->isgd || - mon->m_id == quest_status.leader_m_id); + return (mon->isshk || mon->ispriest || mon->isgd || + mon->m_id == quest_status.leader_m_id); } /* restrict certain special monsters (shopkeepers, aligned priests, @@ -2552,19 +2561,19 @@ validspecmon(mon, mndx) struct monst *mon; int mndx; { - if (mndx == NON_PM) return TRUE; /* caller wants random */ + if (mndx == NON_PM) return TRUE; /* caller wants random */ - if (!accept_newcham_form(mndx)) return FALSE; /* geno'd or !polyok */ + if (!accept_newcham_form(mndx)) return FALSE; /* geno'd or !polyok */ - if (isspecmon(mon)) { - struct permonst *ptr = &mons[mndx]; + if (isspecmon(mon)) { + struct permonst *ptr = &mons[mndx]; - /* reject notake because object manipulation is expected - and nohead because speech capability is expected */ - if (notake(ptr) || !has_head(ptr)) return FALSE; - /* [should we check ptr->msound here too?] */ - } - return TRUE; /* potential new form is ok */ + /* reject notake because object manipulation is expected + and nohead because speech capability is expected */ + if (notake(ptr) || !has_head(ptr)) return FALSE; + /* [should we check ptr->msound here too?] */ + } + return TRUE; /* potential new form is ok */ } /* prevent wizard mode user from specifying invalid vampshifter shape */ @@ -2573,138 +2582,138 @@ validvamp(mon, mndx_p, monclass) struct monst *mon; int *mndx_p, monclass; { - /* simplify caller's usage */ - if (!is_vampshifter(mon)) return validspecmon(mon, *mndx_p); - - if (*mndx_p == PM_VAMPIRE || *mndx_p == PM_VAMPIRE_LORD || - *mndx_p == PM_VLAD_THE_IMPALER) { - /* player picked some type of vampire; use mon's self */ - *mndx_p = mon->cham; - return TRUE; - } - if (mon->cham == PM_VLAD_THE_IMPALER && mon_has_special(mon)) { - /* Vlad with Candelabrum; override choice, then accept it */ - *mndx_p = PM_VLAD_THE_IMPALER; - return TRUE; - } - /* basic vampires can't become wolves; any can become fog or bat */ - if (*mndx_p == PM_WOLF) return (mon->cham != PM_VAMPIRE); - if (*mndx_p == PM_FOG_CLOUD || *mndx_p == PM_VAMPIRE_BAT) return TRUE; - - /* if we get here, specific type was no good; try by class */ - switch (monclass) { - case S_VAMPIRE: *mndx_p = mon->cham; break; - case S_BAT: *mndx_p = PM_VAMPIRE_BAT; break; - case S_VORTEX: *mndx_p = PM_FOG_CLOUD; break; - case S_DOG: if (mon->cham != PM_VAMPIRE) { - *mndx_p = PM_WOLF; - break; - } - /*FALLTHRU*/ - default: *mndx_p = NON_PM; break; - } - return (*mndx_p != NON_PM); + /* simplify caller's usage */ + if (!is_vampshifter(mon)) return validspecmon(mon, *mndx_p); + + if (*mndx_p == PM_VAMPIRE || *mndx_p == PM_VAMPIRE_LORD || + *mndx_p == PM_VLAD_THE_IMPALER) { + /* player picked some type of vampire; use mon's self */ + *mndx_p = mon->cham; + return TRUE; + } + if (mon->cham == PM_VLAD_THE_IMPALER && mon_has_special(mon)) { + /* Vlad with Candelabrum; override choice, then accept it */ + *mndx_p = PM_VLAD_THE_IMPALER; + return TRUE; + } + /* basic vampires can't become wolves; any can become fog or bat */ + if (*mndx_p == PM_WOLF) return (mon->cham != PM_VAMPIRE); + if (*mndx_p == PM_FOG_CLOUD || *mndx_p == PM_VAMPIRE_BAT) return TRUE; + + /* if we get here, specific type was no good; try by class */ + switch (monclass) { + case S_VAMPIRE: *mndx_p = mon->cham; break; + case S_BAT: *mndx_p = PM_VAMPIRE_BAT; break; + case S_VORTEX: *mndx_p = PM_FOG_CLOUD; break; + case S_DOG: if (mon->cham != PM_VAMPIRE) { + *mndx_p = PM_WOLF; + break; + } + /*FALLTHRU*/ + default: *mndx_p = NON_PM; break; + } + return (*mndx_p != NON_PM); } int select_newcham_form(mon) struct monst *mon; { - int mndx = NON_PM, tryct; - - switch (mon->cham) { - case PM_SANDESTIN: - if (rn2(7)) mndx = pick_nasty(); - break; - case PM_DOPPELGANGER: - if (!rn2(7)) { - mndx = pick_nasty(); - } else if (rn2(3)) { /* role monsters */ - mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, - PM_ARCHEOLOGIST); - } else if (!rn2(3)) { /* quest guardians */ - mndx = rn1(PM_APPRENTICE - PM_STUDENT + 1, - PM_STUDENT); - /* avoid own role's guardian */ - if (mndx == urole.guardnum) mndx = NON_PM; - } else { /* general humanoids */ - tryct = 5; - do { - mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); - if (humanoid(&mons[mndx]) && polyok(&mons[mndx])) break; - } while (--tryct > 0); - if (!tryct) mndx = NON_PM; - } - break; - case PM_CHAMELEON: - if (!rn2(3)) mndx = pick_animal(); - break; - case PM_VLAD_THE_IMPALER: - case PM_VAMPIRE_LORD: - case PM_VAMPIRE: - mndx = pickvampshape(mon); - break; - case NON_PM: /* ordinary */ - { - struct obj *m_armr = which_armor(mon, W_ARM); - - if (m_armr && Is_dragon_scales(m_armr)) - mndx = (int)(Dragon_scales_to_pm(m_armr) - mons); - else if (m_armr && Is_dragon_mail(m_armr)) - mndx = (int)(Dragon_mail_to_pm(m_armr) - mons); - } - break; - } - /* for debugging: allow control of polymorphed monster */ - if (wizard && iflags.mon_polycontrol) { - char pprompt[BUFSZ], buf[BUFSZ]; - int monclass; - - Sprintf(pprompt, - "Change %s @ <%d,%d> into what kind of monster?", - noit_mon_nam(mon), (int)mon->mx, (int)mon->my); - tryct = 5; - do { - monclass = 0; - getlin(pprompt, buf); - mungspaces(buf); - /* for ESC, take form selected above (might be NON_PM) */ - if (*buf == '\033') break; - /* for "*", use NON_PM to pick an arbitrary shape below */ - if (!strcmp(buf, "*") || !strcmp(buf, "random")) { - mndx = NON_PM; - break; - } - mndx = name_to_mon(buf); - if (mndx == NON_PM) { - /* didn't get a type, so check whether it's a class - (single letter or text match with def_monsyms[]) */ - monclass = name_to_monclass(buf, &mndx); - if (monclass && mndx == NON_PM) - mndx = mkclass_poly(monclass); - } - if (mndx >= LOW_PM) { - /* got a specific type of monster; use it if we can */ - if (validvamp(mon, &mndx, monclass)) break; - /* can't; revert to random in case we exhaust tryct */ - mndx = NON_PM; - } - - pline("It can't become that."); - } while (--tryct > 0); - if (!tryct) pline1(thats_enough_tries); - if (is_vampshifter(mon) && !validvamp(mon, &mndx, monclass)) - mndx = pickvampshape(mon); /* don't resort to arbitrary */ - } - - /* if no form was specified above, pick one at random now */ - if (mndx == NON_PM) { - tryct = 50; - do { - mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); - } while (--tryct > 0 && !validspecmon(mon, mndx)); - } - return mndx; + int mndx = NON_PM, tryct; + + switch (mon->cham) { + case PM_SANDESTIN: + if (rn2(7)) mndx = pick_nasty(); + break; + case PM_DOPPELGANGER: + if (!rn2(7)) { + mndx = pick_nasty(); + } else if (rn2(3)) { /* role monsters */ + mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, + PM_ARCHEOLOGIST); + } else if (!rn2(3)) { /* quest guardians */ + mndx = rn1(PM_APPRENTICE - PM_STUDENT + 1, + PM_STUDENT); + /* avoid own role's guardian */ + if (mndx == urole.guardnum) mndx = NON_PM; + } else { /* general humanoids */ + tryct = 5; + do { + mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); + if (humanoid(&mons[mndx]) && polyok(&mons[mndx])) break; + } while (--tryct > 0); + if (!tryct) mndx = NON_PM; + } + break; + case PM_CHAMELEON: + if (!rn2(3)) mndx = pick_animal(); + break; + case PM_VLAD_THE_IMPALER: + case PM_VAMPIRE_LORD: + case PM_VAMPIRE: + mndx = pickvampshape(mon); + break; + case NON_PM: /* ordinary */ + { + struct obj *m_armr = which_armor(mon, W_ARM); + + if (m_armr && Is_dragon_scales(m_armr)) + mndx = (int)(Dragon_scales_to_pm(m_armr) - mons); + else if (m_armr && Is_dragon_mail(m_armr)) + mndx = (int)(Dragon_mail_to_pm(m_armr) - mons); + } + break; + } + /* for debugging: allow control of polymorphed monster */ + if (wizard && iflags.mon_polycontrol) { + char pprompt[BUFSZ], buf[BUFSZ]; + int monclass; + + Sprintf(pprompt, + "Change %s @ <%d,%d> into what kind of monster?", + noit_mon_nam(mon), (int)mon->mx, (int)mon->my); + tryct = 5; + do { + monclass = 0; + getlin(pprompt, buf); + mungspaces(buf); + /* for ESC, take form selected above (might be NON_PM) */ + if (*buf == '\033') break; + /* for "*", use NON_PM to pick an arbitrary shape below */ + if (!strcmp(buf, "*") || !strcmp(buf, "random")) { + mndx = NON_PM; + break; + } + mndx = name_to_mon(buf); + if (mndx == NON_PM) { + /* didn't get a type, so check whether it's a class + (single letter or text match with def_monsyms[]) */ + monclass = name_to_monclass(buf, &mndx); + if (monclass && mndx == NON_PM) + mndx = mkclass_poly(monclass); + } + if (mndx >= LOW_PM) { + /* got a specific type of monster; use it if we can */ + if (validvamp(mon, &mndx, monclass)) break; + /* can't; revert to random in case we exhaust tryct */ + mndx = NON_PM; + } + + pline("It can't become that."); + } while (--tryct > 0); + if (!tryct) pline1(thats_enough_tries); + if (is_vampshifter(mon) && !validvamp(mon, &mndx, monclass)) + mndx = pickvampshape(mon); /* don't resort to arbitrary */ + } + + /* if no form was specified above, pick one at random now */ + if (mndx == NON_PM) { + tryct = 50; + do { + mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); + } while (--tryct > 0 && !validspecmon(mon, mndx)); + } + return mndx; } /* this used to be inline within newcham() but monpolycontrol needs it too */ @@ -2712,18 +2721,18 @@ STATIC_OVL struct permonst * accept_newcham_form(mndx) int mndx; { - struct permonst *mdat; + struct permonst *mdat; - if (mndx == NON_PM) return 0; - mdat = &mons[mndx]; - if ((mvitals[mndx].mvflags & G_GENOD) != 0) return 0; - if (is_placeholder(mdat)) return 0; - /* select_newcham_form() might deliberately pick a player - character type (random selection never does) which - polyok() rejects, so we need a special case here */ - if (is_mplayer(mdat)) return mdat; - /* polyok() rules out M2_PNAME, M2_WERE, and all humans except Kops */ - return polyok(mdat) ? mdat : 0; + if (mndx == NON_PM) return 0; + mdat = &mons[mndx]; + if ((mvitals[mndx].mvflags & G_GENOD) != 0) return 0; + if (is_placeholder(mdat)) return 0; + /* select_newcham_form() might deliberately pick a player + character type (random selection never does) which + polyok() rejects, so we need a special case here */ + if (is_mplayer(mdat)) return mdat; + /* polyok() rules out M2_PNAME, M2_WERE, and all humans except Kops */ + return polyok(mdat) ? mdat : 0; } /* make a chameleon take on another shape, or a polymorph target @@ -2736,185 +2745,185 @@ struct permonst *mdat; boolean polyspot; /* change is the result of wand or spell of polymorph */ boolean msg; /* "The oldmon turns into a newmon!" */ { - int hpn, hpd; - int mndx, tryct; - struct permonst *olddata = mtmp->data; - char oldname[BUFSZ], newname[BUFSZ]; - - /* Riders are immune to polymorph and green slime */ - if (is_rider(mtmp->data)) return 0; - - if (msg) { - /* like Monnam() but never mention saddle */ - Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *)0, - SUPPRESS_SADDLE, FALSE)); - oldname[0] = highc(oldname[0]); - } - - /* mdat = 0 -> caller wants a random monster shape */ - if (mdat == 0) { - /* select_newcham_form() loops when resorting to random but - it doesn't always pick that so we still retry here too */ - tryct = 20; - do { - mndx = select_newcham_form(mtmp); - mdat = accept_newcham_form(mndx); - if (mdat) break; - } while (--tryct > 0); - if (!tryct) return 0; - } else if (mvitals[monsndx(mdat)].mvflags & G_GENOD) - return(0); /* passed in mdat is genocided */ - - if(is_male(mdat)) { - if(mtmp->female) mtmp->female = FALSE; - } else if (is_female(mdat)) { - if(!mtmp->female) mtmp->female = TRUE; - } else if (!is_neuter(mdat)) { - if(!rn2(10)) mtmp->female = !mtmp->female; - } - - if (In_endgame(&u.uz) && is_mplayer(olddata) && has_mname(mtmp)) { - /* mplayers start out as "Foo the Bar", but some of the - * titles are inappropriate when polymorphed, particularly - * into the opposite sex. players don't use ranks when - * polymorphed, so dropping the rank for mplayers seems - * reasonable. - */ - char *p = index(MNAME(mtmp), ' '); - if (p) { - *p = '\0'; - } - } - - if(mdat == mtmp->data) return(0); /* still the same monster */ - - if(mtmp->wormno) { /* throw tail away */ - wormgone(mtmp); - place_monster(mtmp, mtmp->mx, mtmp->my); - } - if (mtmp->m_ap_type && mdat->mlet != S_MIMIC) - seemimic(mtmp); /* revert to normal monster */ - - /* (this code used to try to adjust the monster's health based on - a normal one of its type but there are too many special cases - which need to handled in order to do that correctly, so just - give the new form the same proportion of HP as its old one had) */ - hpn = mtmp->mhp; - hpd = mtmp->mhpmax; - /* set level and hit points */ - newmonhp(mtmp, monsndx(mdat)); - /* new hp: same fraction of max as before */ + int hpn, hpd; + int mndx, tryct; + struct permonst *olddata = mtmp->data; + char oldname[BUFSZ], newname[BUFSZ]; + + /* Riders are immune to polymorph and green slime */ + if (is_rider(mtmp->data)) return 0; + + if (msg) { + /* like Monnam() but never mention saddle */ + Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *)0, + SUPPRESS_SADDLE, FALSE)); + oldname[0] = highc(oldname[0]); + } + + /* mdat = 0 -> caller wants a random monster shape */ + if (mdat == 0) { + /* select_newcham_form() loops when resorting to random but + it doesn't always pick that so we still retry here too */ + tryct = 20; + do { + mndx = select_newcham_form(mtmp); + mdat = accept_newcham_form(mndx); + if (mdat) break; + } while (--tryct > 0); + if (!tryct) return 0; + } else if (mvitals[monsndx(mdat)].mvflags & G_GENOD) + return(0); /* passed in mdat is genocided */ + + if(is_male(mdat)) { + if(mtmp->female) mtmp->female = FALSE; + } else if (is_female(mdat)) { + if(!mtmp->female) mtmp->female = TRUE; + } else if (!is_neuter(mdat)) { + if(!rn2(10)) mtmp->female = !mtmp->female; + } + + if (In_endgame(&u.uz) && is_mplayer(olddata) && has_mname(mtmp)) { + /* mplayers start out as "Foo the Bar", but some of the + * titles are inappropriate when polymorphed, particularly + * into the opposite sex. players don't use ranks when + * polymorphed, so dropping the rank for mplayers seems + * reasonable. + */ + char *p = index(MNAME(mtmp), ' '); + if (p) { + *p = '\0'; + } + } + + if(mdat == mtmp->data) return(0); /* still the same monster */ + + if(mtmp->wormno) { /* throw tail away */ + wormgone(mtmp); + place_monster(mtmp, mtmp->mx, mtmp->my); + } + if (mtmp->m_ap_type && mdat->mlet != S_MIMIC) + seemimic(mtmp); /* revert to normal monster */ + + /* (this code used to try to adjust the monster's health based on + a normal one of its type but there are too many special cases + which need to handled in order to do that correctly, so just + give the new form the same proportion of HP as its old one had) */ + hpn = mtmp->mhp; + hpd = mtmp->mhpmax; + /* set level and hit points */ + newmonhp(mtmp, monsndx(mdat)); + /* new hp: same fraction of max as before */ #ifndef LINT - mtmp->mhp = (int)(((long)hpn * (long)mtmp->mhp) / (long)hpd); + mtmp->mhp = (int)(((long)hpn * (long)mtmp->mhp) / (long)hpd); #endif - /* sanity check (potentional overflow) */ - if (mtmp->mhp < 0 || mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; - /* unlikely but not impossible; a 1HD creature with 1HP that changes - into a 0HD creature will require this statement */ - if (!mtmp->mhp) mtmp->mhp = 1; - - /* take on the new form... */ - set_mon_data(mtmp, mdat, 0); - - if (emits_light(olddata) != emits_light(mtmp->data)) { - /* used to give light, now doesn't, or vice versa, - or light's range has changed */ - if (emits_light(olddata)) - del_light_source(LS_MONSTER, monst_to_any(mtmp)); - if (emits_light(mtmp->data)) - new_light_source(mtmp->mx, mtmp->my, emits_light(mtmp->data), - LS_MONSTER, monst_to_any(mtmp)); - } - if (!mtmp->perminvis || pm_invisible(olddata)) - mtmp->perminvis = pm_invisible(mdat); - mtmp->minvis = mtmp->invis_blkd ? 0 : mtmp->perminvis; - if (mtmp->mundetected) (void) hideunder(mtmp); - if (u.ustuck == mtmp) { - if(u.uswallow) { - if(!attacktype(mdat,AT_ENGL)) { - /* Does mdat care? */ - if (!noncorporeal(mdat) && !amorphous(mdat) && - !is_whirly(mdat) && - (mdat != &mons[PM_YELLOW_LIGHT])) { - You("break out of %s%s!", mon_nam(mtmp), - (is_animal(mdat)? - "'s stomach" : "")); - mtmp->mhp = 1; /* almost dead */ - } - expels(mtmp, olddata, FALSE); - } else { - /* update swallow glyphs for new monster */ - swallowed(0); - } - } else if (!sticks(mdat) && !sticks(youmonst.data)) - unstuck(mtmp); - } + /* sanity check (potentional overflow) */ + if (mtmp->mhp < 0 || mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; + /* unlikely but not impossible; a 1HD creature with 1HP that changes + into a 0HD creature will require this statement */ + if (!mtmp->mhp) mtmp->mhp = 1; + + /* take on the new form... */ + set_mon_data(mtmp, mdat, 0); + + if (emits_light(olddata) != emits_light(mtmp->data)) { + /* used to give light, now doesn't, or vice versa, + or light's range has changed */ + if (emits_light(olddata)) + del_light_source(LS_MONSTER, monst_to_any(mtmp)); + if (emits_light(mtmp->data)) + new_light_source(mtmp->mx, mtmp->my, emits_light(mtmp->data), + LS_MONSTER, monst_to_any(mtmp)); + } + if (!mtmp->perminvis || pm_invisible(olddata)) + mtmp->perminvis = pm_invisible(mdat); + mtmp->minvis = mtmp->invis_blkd ? 0 : mtmp->perminvis; + if (mtmp->mundetected) (void) hideunder(mtmp); + if (u.ustuck == mtmp) { + if(u.uswallow) { + if(!attacktype(mdat,AT_ENGL)) { + /* Does mdat care? */ + if (!noncorporeal(mdat) && !amorphous(mdat) && + !is_whirly(mdat) && + (mdat != &mons[PM_YELLOW_LIGHT])) { + You("break out of %s%s!", mon_nam(mtmp), + (is_animal(mdat)? + "'s stomach" : "")); + mtmp->mhp = 1; /* almost dead */ + } + expels(mtmp, olddata, FALSE); + } else { + /* update swallow glyphs for new monster */ + swallowed(0); + } + } else if (!sticks(mdat) && !sticks(youmonst.data)) + unstuck(mtmp); + } #ifndef DCC30_BUG - if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) { + if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) { #else - /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the - * same expression. - */ - if (mdat == &mons[PM_LONG_WORM] && - (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) { + /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the + * same expression. + */ + if (mdat == &mons[PM_LONG_WORM] && + (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) { #endif - /* we can now create worms with tails - 11/91 */ - initworm(mtmp, rn2(5)); - if (count_wsegs(mtmp)) - place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my); - } - - newsym(mtmp->mx,mtmp->my); - - if (msg) { - char *save_mname = 0; - - if (has_mname(mtmp)) { - save_mname = MNAME(mtmp); - MNAME(mtmp) = (char *)0; - } - Strcpy(newname, - (mdat == &mons[PM_GREEN_SLIME]) ? "slime" : - x_monnam(mtmp, ARTICLE_A, (char *)0,SUPPRESS_SADDLE, FALSE)); - if (!strcmpi(oldname,"it") && !strcmpi(newname,"it")) - (void) usmellmon(mdat); - else - pline("%s turns into %s!", oldname, newname); - if (save_mname) MNAME(mtmp) = save_mname; - } - - possibly_unwield(mtmp, polyspot); /* might lose use of weapon */ - mon_break_armor(mtmp, polyspot); - if (!(mtmp->misc_worn_check & W_ARMG)) - mselftouch(mtmp, "No longer petrify-resistant, ", - !context.mon_moving); - m_dowear(mtmp, FALSE); - - /* This ought to re-test can_carry() on each item in the inventory - * rather than just checking ex-giants & boulders, but that'd be - * pretty expensive to perform. If implemented, then perhaps - * minvent should be sorted in order to drop heaviest items first. - */ - /* former giants can't continue carrying boulders */ - if (mtmp->minvent && !throws_rocks(mdat)) { - register struct obj *otmp, *otmp2; - - for (otmp = mtmp->minvent; otmp; otmp = otmp2) { - otmp2 = otmp->nobj; - if (otmp->otyp == BOULDER) { - /* this keeps otmp from being polymorphed in the - same zap that the monster that held it is polymorphed */ - if (polyspot) bypass_obj(otmp); - obj_extract_self(otmp); - /* probably ought to give some "drop" message here */ - if (flooreffects(otmp, mtmp->mx, mtmp->my, "")) continue; - place_object(otmp, mtmp->mx, mtmp->my); - } - } - } - - return(1); + /* we can now create worms with tails - 11/91 */ + initworm(mtmp, rn2(5)); + if (count_wsegs(mtmp)) + place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my); + } + + newsym(mtmp->mx,mtmp->my); + + if (msg) { + char *save_mname = 0; + + if (has_mname(mtmp)) { + save_mname = MNAME(mtmp); + MNAME(mtmp) = (char *)0; + } + Strcpy(newname, + (mdat == &mons[PM_GREEN_SLIME]) ? "slime" : + x_monnam(mtmp, ARTICLE_A, (char *)0,SUPPRESS_SADDLE, FALSE)); + if (!strcmpi(oldname,"it") && !strcmpi(newname,"it")) + (void) usmellmon(mdat); + else + pline("%s turns into %s!", oldname, newname); + if (save_mname) MNAME(mtmp) = save_mname; + } + + possibly_unwield(mtmp, polyspot); /* might lose use of weapon */ + mon_break_armor(mtmp, polyspot); + if (!(mtmp->misc_worn_check & W_ARMG)) + mselftouch(mtmp, "No longer petrify-resistant, ", + !context.mon_moving); + m_dowear(mtmp, FALSE); + + /* This ought to re-test can_carry() on each item in the inventory + * rather than just checking ex-giants & boulders, but that'd be + * pretty expensive to perform. If implemented, then perhaps + * minvent should be sorted in order to drop heaviest items first. + */ + /* former giants can't continue carrying boulders */ + if (mtmp->minvent && !throws_rocks(mdat)) { + register struct obj *otmp, *otmp2; + + for (otmp = mtmp->minvent; otmp; otmp = otmp2) { + otmp2 = otmp->nobj; + if (otmp->otyp == BOULDER) { + /* this keeps otmp from being polymorphed in the + same zap that the monster that held it is polymorphed */ + if (polyspot) bypass_obj(otmp); + obj_extract_self(otmp); + /* probably ought to give some "drop" message here */ + if (flooreffects(otmp, mtmp->mx, mtmp->my, "")) continue; + place_object(otmp, mtmp->mx, mtmp->my); + } + } + } + + return(1); } /* sometimes an egg will be special */ @@ -2940,9 +2949,9 @@ int mnum; * grow into queen bees. Ditto for [winged-]gargoyles. */ if (mnum == PM_KILLER_BEE || mnum == PM_GARGOYLE || - (lays_eggs(&mons[mnum]) && (BREEDER_EGG || - (mnum != PM_QUEEN_BEE && mnum != PM_WINGED_GARGOYLE)))) - return mnum; + (lays_eggs(&mons[mnum]) && (BREEDER_EGG || + (mnum != PM_QUEEN_BEE && mnum != PM_WINGED_GARGOYLE)))) + return mnum; return NON_PM; } @@ -2953,8 +2962,8 @@ int mnum; /* parent monster; caller must handle lays_eggs() check */ boolean force_ordinary; { if (force_ordinary || !BREEDER_EGG) { - if (mnum == PM_QUEEN_BEE) mnum = PM_KILLER_BEE; - else if (mnum == PM_WINGED_GARGOYLE) mnum = PM_GARGOYLE; + if (mnum == PM_QUEEN_BEE) mnum = PM_KILLER_BEE; + else if (mnum == PM_WINGED_GARGOYLE) mnum = PM_GARGOYLE; } return mnum; } @@ -2966,18 +2975,18 @@ dead_species(m_idx, egg) int m_idx; boolean egg; { - /* - * For monsters with both baby and adult forms, genociding either - * form kills all eggs of that monster. Monsters with more than - * two forms (small->large->giant mimics) are more or less ignored; - * fortunately, none of them have eggs. Species extinction due to - * overpopulation does not kill eggs. - */ - return (boolean) - (m_idx >= LOW_PM && - ((mvitals[m_idx].mvflags & G_GENOD) != 0 || - (egg && - (mvitals[big_to_little(m_idx)].mvflags & G_GENOD) != 0))); + /* + * For monsters with both baby and adult forms, genociding either + * form kills all eggs of that monster. Monsters with more than + * two forms (small->large->giant mimics) are more or less ignored; + * fortunately, none of them have eggs. Species extinction due to + * overpopulation does not kill eggs. + */ + return (boolean) + (m_idx >= LOW_PM && + ((mvitals[m_idx].mvflags & G_GENOD) != 0 || + (egg && + (mvitals[big_to_little(m_idx)].mvflags & G_GENOD) != 0))); } /* kill off any eggs of genocided monsters */ @@ -2985,70 +2994,70 @@ STATIC_OVL void kill_eggs(obj_list) struct obj *obj_list; { - struct obj *otmp; - - for (otmp = obj_list; otmp; otmp = otmp->nobj) - if (otmp->otyp == EGG) { - if (dead_species(otmp->corpsenm, TRUE)) { - /* - * It seems we could also just catch this when - * it attempted to hatch, so we wouldn't have to - * search all of the objlists.. or stop all - * hatch timers based on a corpsenm. - */ - kill_egg(otmp); - } + struct obj *otmp; + + for (otmp = obj_list; otmp; otmp = otmp->nobj) + if (otmp->otyp == EGG) { + if (dead_species(otmp->corpsenm, TRUE)) { + /* + * It seems we could also just catch this when + * it attempted to hatch, so we wouldn't have to + * search all of the objlists.. or stop all + * hatch timers based on a corpsenm. + */ + kill_egg(otmp); + } #if 0 /* not used */ - } else if (otmp->otyp == TIN) { - if (dead_species(otmp->corpsenm, FALSE)) - otmp->corpsenm = NON_PM; /* empty tin */ - } else if (otmp->otyp == CORPSE) { - if (dead_species(otmp->corpsenm, FALSE)) - ; /* not yet implemented... */ + } else if (otmp->otyp == TIN) { + if (dead_species(otmp->corpsenm, FALSE)) + otmp->corpsenm = NON_PM; /* empty tin */ + } else if (otmp->otyp == CORPSE) { + if (dead_species(otmp->corpsenm, FALSE)) + ; /* not yet implemented... */ #endif - } else if (Has_contents(otmp)) { - kill_eggs(otmp->cobj); - } + } else if (Has_contents(otmp)) { + kill_eggs(otmp->cobj); + } } /* kill all members of genocided species */ void kill_genocided_monsters() { - struct monst *mtmp, *mtmp2; - boolean kill_cham; - int mndx; - - /* - * Called during genocide, and again upon level change. The latter - * catches up with any migrating monsters as they finally arrive at - * their intended destinations, so possessions get deposited there. - * - * Chameleon handling: - * 1) if chameleons have been genocided, destroy them - * regardless of current form; - * 2) otherwise, force every chameleon which is imitating - * any genocided species to take on a new form. - */ - for (mtmp = fmon; mtmp; mtmp = mtmp2) { - mtmp2 = mtmp->nmon; - if (DEADMONSTER(mtmp)) continue; - mndx = monsndx(mtmp->data); - kill_cham = (mtmp->cham >= LOW_PM && - (mvitals[mtmp->cham].mvflags & G_GENOD)); - if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham) { - if (mtmp->cham >= LOW_PM && !kill_cham) - (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); - else - mondead(mtmp); - } - if (mtmp->minvent) kill_eggs(mtmp->minvent); - } - - kill_eggs(invent); - kill_eggs(fobj); - kill_eggs(migrating_objs); - kill_eggs(level.buriedobjlist); + struct monst *mtmp, *mtmp2; + boolean kill_cham; + int mndx; + + /* + * Called during genocide, and again upon level change. The latter + * catches up with any migrating monsters as they finally arrive at + * their intended destinations, so possessions get deposited there. + * + * Chameleon handling: + * 1) if chameleons have been genocided, destroy them + * regardless of current form; + * 2) otherwise, force every chameleon which is imitating + * any genocided species to take on a new form. + */ + for (mtmp = fmon; mtmp; mtmp = mtmp2) { + mtmp2 = mtmp->nmon; + if (DEADMONSTER(mtmp)) continue; + mndx = monsndx(mtmp->data); + kill_cham = (mtmp->cham >= LOW_PM && + (mvitals[mtmp->cham].mvflags & G_GENOD)); + if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham) { + if (mtmp->cham >= LOW_PM && !kill_cham) + (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); + else + mondead(mtmp); + } + if (mtmp->minvent) kill_eggs(mtmp->minvent); + } + + kill_eggs(invent); + kill_eggs(fobj); + kill_eggs(migrating_objs); + kill_eggs(level.buriedobjlist); } void @@ -3059,25 +3068,25 @@ int damtype, dam; int heal = 0, slow = 0; if (mon->data == &mons[PM_FLESH_GOLEM]) { - if (damtype == AD_ELEC) heal = dam / 6; - else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1; + if (damtype == AD_ELEC) heal = dam / 6; + else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1; } else if (mon->data == &mons[PM_IRON_GOLEM]) { - if (damtype == AD_ELEC) slow = 1; - else if (damtype == AD_FIRE) heal = dam; + if (damtype == AD_ELEC) slow = 1; + else if (damtype == AD_FIRE) heal = dam; } else { - return; + return; } if (slow) { - if (mon->mspeed != MSLOW) - mon_adjust_speed(mon, -1, (struct obj *)0); + if (mon->mspeed != MSLOW) + mon_adjust_speed(mon, -1, (struct obj *)0); } if (heal) { - if (mon->mhp < mon->mhpmax) { - mon->mhp += dam; - if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; - if (cansee(mon->mx, mon->my)) - pline("%s seems healthier.", Monnam(mon)); - } + if (mon->mhp < mon->mhpmax) { + mon->mhp += dam; + if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; + if (cansee(mon->mx, mon->my)) + pline("%s seems healthier.", Monnam(mon)); + } } } @@ -3085,55 +3094,55 @@ boolean angry_guards(silent) register boolean silent; { - register struct monst *mtmp; - register int ct = 0, nct = 0, sct = 0, slct = 0; - - for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - if((mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) - && mtmp->mpeaceful) { - ct++; - if(cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) { - if (distu(mtmp->mx, mtmp->my) == 2) nct++; - else sct++; - } - if (mtmp->msleeping || mtmp->mfrozen) { - slct++; - mtmp->msleeping = mtmp->mfrozen = 0; - } - mtmp->mpeaceful = 0; - } - } - if(ct) { - if(!silent) { /* do we want pline msgs? */ - if(slct) pline_The("guard%s wake%s up!", - slct > 1 ? "s" : "", slct == 1 ? "s" : ""); - if(nct || sct) { - if(nct) pline_The("guard%s get%s angry!", - nct == 1 ? "" : "s", nct == 1 ? "s" : ""); - else if(!Blind) - You_see("%sangry guard%s approaching!", - sct == 1 ? "an " : "", sct > 1 ? "s" : ""); - } else - You_hear("the shrill sound of a guard's whistle."); - } - return(TRUE); - } - return(FALSE); + register struct monst *mtmp; + register int ct = 0, nct = 0, sct = 0, slct = 0; + + for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if((mtmp->data == &mons[PM_WATCHMAN] || + mtmp->data == &mons[PM_WATCH_CAPTAIN]) + && mtmp->mpeaceful) { + ct++; + if(cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) { + if (distu(mtmp->mx, mtmp->my) == 2) nct++; + else sct++; + } + if (mtmp->msleeping || mtmp->mfrozen) { + slct++; + mtmp->msleeping = mtmp->mfrozen = 0; + } + mtmp->mpeaceful = 0; + } + } + if(ct) { + if(!silent) { /* do we want pline msgs? */ + if(slct) pline_The("guard%s wake%s up!", + slct > 1 ? "s" : "", slct == 1 ? "s" : ""); + if(nct || sct) { + if(nct) pline_The("guard%s get%s angry!", + nct == 1 ? "" : "s", nct == 1 ? "s" : ""); + else if(!Blind) + You_see("%sangry guard%s approaching!", + sct == 1 ? "an " : "", sct > 1 ? "s" : ""); + } else + You_hear("the shrill sound of a guard's whistle."); + } + return(TRUE); + } + return(FALSE); } void pacify_guards() { - register struct monst *mtmp; + register struct monst *mtmp; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - if (mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) - mtmp->mpeaceful = 1; - } + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (mtmp->data == &mons[PM_WATCHMAN] || + mtmp->data == &mons[PM_WATCH_CAPTAIN]) + mtmp->mpeaceful = 1; + } } void @@ -3141,138 +3150,138 @@ mimic_hit_msg(mtmp, otyp) struct monst *mtmp; short otyp; { - short ap = mtmp->mappearance; - - switch(mtmp->m_ap_type) { - case M_AP_NOTHING: - case M_AP_FURNITURE: - case M_AP_MONSTER: - break; - case M_AP_OBJECT: - if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) { - pline("%s seems a more vivid %s than before.", - The(simple_typename(ap)), - c_obj_colors[objects[ap].oc_color]); - } - break; - } + short ap = mtmp->mappearance; + + switch(mtmp->m_ap_type) { + case M_AP_NOTHING: + case M_AP_FURNITURE: + case M_AP_MONSTER: + break; + case M_AP_OBJECT: + if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) { + pline("%s seems a more vivid %s than before.", + The(simple_typename(ap)), + c_obj_colors[objects[ap].oc_color]); + } + break; + } } boolean usmellmon(mdat) struct permonst *mdat; { - int mndx; - boolean nonspecific = FALSE; - boolean msg_given = FALSE; - - if (mdat) { - if (!olfaction(youmonst.data)) return FALSE; - mndx = monsndx(mdat); - switch (mndx) { - case PM_ROTHE: - case PM_MINOTAUR: - You("notice a bovine smell."); - msg_given = TRUE; - break; - case PM_CAVEMAN: - case PM_CAVEWOMAN: - case PM_BARBARIAN: - case PM_NEANDERTHAL: - You("smell body odor."); - msg_given = TRUE; - break; + int mndx; + boolean nonspecific = FALSE; + boolean msg_given = FALSE; + + if (mdat) { + if (!olfaction(youmonst.data)) return FALSE; + mndx = monsndx(mdat); + switch (mndx) { + case PM_ROTHE: + case PM_MINOTAUR: + You("notice a bovine smell."); + msg_given = TRUE; + break; + case PM_CAVEMAN: + case PM_CAVEWOMAN: + case PM_BARBARIAN: + case PM_NEANDERTHAL: + You("smell body odor."); + msg_given = TRUE; + break; /* - case PM_PESTILENCE: - case PM_FAMINE: - case PM_DEATH: - break; + case PM_PESTILENCE: + case PM_FAMINE: + case PM_DEATH: + break; */ - case PM_HORNED_DEVIL: - case PM_BALROG: - case PM_ASMODEUS: - case PM_DISPATER: - case PM_YEENOGHU: - case PM_ORCUS: - break; - case PM_HUMAN_WEREJACKAL: - case PM_HUMAN_WERERAT: - case PM_HUMAN_WEREWOLF: - case PM_WEREJACKAL: - case PM_WERERAT: - case PM_WEREWOLF: - case PM_OWLBEAR: - You("detect an odor reminiscent of an animal's den."); - msg_given = TRUE; - break; + case PM_HORNED_DEVIL: + case PM_BALROG: + case PM_ASMODEUS: + case PM_DISPATER: + case PM_YEENOGHU: + case PM_ORCUS: + break; + case PM_HUMAN_WEREJACKAL: + case PM_HUMAN_WERERAT: + case PM_HUMAN_WEREWOLF: + case PM_WEREJACKAL: + case PM_WERERAT: + case PM_WEREWOLF: + case PM_OWLBEAR: + You("detect an odor reminiscent of an animal's den."); + msg_given = TRUE; + break; /* - case PM_PURPLE_WORM: - break; + case PM_PURPLE_WORM: + break; */ - case PM_STEAM_VORTEX: - You("smell steam."); - msg_given = TRUE; - break; - case PM_GREEN_SLIME: - pline("%s stinks.", Something); - msg_given = TRUE; - break; - case PM_VIOLET_FUNGUS: - case PM_SHRIEKER: - You("smell mushrooms."); - msg_given = TRUE; - break; - /* These are here to avoid triggering the - nonspecific treatment through the default case below*/ - case PM_WHITE_UNICORN: - case PM_GRAY_UNICORN: - case PM_BLACK_UNICORN: - case PM_JELLYFISH: - break; - default: - nonspecific = TRUE; - break; - } - - if (nonspecific) switch(mdat->mlet) { - case S_DOG: - You("notice a dog smell."); - msg_given = TRUE; - break; - case S_DRAGON: - You("smell a dragon!"); - msg_given = TRUE; - break; - case S_FUNGUS: - pline("%s smells moldy.", Something); - msg_given = TRUE; - break; - case S_UNICORN: - You("detect a%s odor reminiscent of a stable.", - (mndx == PM_PONY) ? "n" : " strong"); - msg_given = TRUE; - break; - case S_ZOMBIE: - You("smell rotting flesh."); - msg_given = TRUE; - break; - case S_EEL: - You("smell fish."); - msg_given = TRUE; - break; - case S_ORC: - if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) - You("notice an attractive smell."); - else - pline( - "A foul stench makes you feel a little nauseated."); - msg_given = TRUE; - break; - default: - break; - } - } - return (msg_given) ? TRUE : FALSE; + case PM_STEAM_VORTEX: + You("smell steam."); + msg_given = TRUE; + break; + case PM_GREEN_SLIME: + pline("%s stinks.", Something); + msg_given = TRUE; + break; + case PM_VIOLET_FUNGUS: + case PM_SHRIEKER: + You("smell mushrooms."); + msg_given = TRUE; + break; + /* These are here to avoid triggering the + nonspecific treatment through the default case below*/ + case PM_WHITE_UNICORN: + case PM_GRAY_UNICORN: + case PM_BLACK_UNICORN: + case PM_JELLYFISH: + break; + default: + nonspecific = TRUE; + break; + } + + if (nonspecific) switch(mdat->mlet) { + case S_DOG: + You("notice a dog smell."); + msg_given = TRUE; + break; + case S_DRAGON: + You("smell a dragon!"); + msg_given = TRUE; + break; + case S_FUNGUS: + pline("%s smells moldy.", Something); + msg_given = TRUE; + break; + case S_UNICORN: + You("detect a%s odor reminiscent of a stable.", + (mndx == PM_PONY) ? "n" : " strong"); + msg_given = TRUE; + break; + case S_ZOMBIE: + You("smell rotting flesh."); + msg_given = TRUE; + break; + case S_EEL: + You("smell fish."); + msg_given = TRUE; + break; + case S_ORC: + if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) + You("notice an attractive smell."); + else + pline( + "A foul stench makes you feel a little nauseated."); + msg_given = TRUE; + break; + default: + break; + } + } + return (msg_given) ? TRUE : FALSE; } /*mon.c*/ diff --git a/src/monst.c b/src/monst.c index d6b843b6c..3c1bde26e 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1820,7 +1820,7 @@ struct permonst _mons2[] = { * Puddings */ MON("gray ooze", S_PUDDING, - LVL(3, 1, 8, 0, 0), (G_GENO|2), + LVL(3, 1, 8, 0, 0), (G_GENO|G_NOCORPSE|2), A(ATTK(AT_BITE, AD_RUST, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, MS_SILENT, MZ_MEDIUM), @@ -1829,7 +1829,7 @@ struct permonst _mons2[] = { M1_MINDLESS|M1_OMNIVORE|M1_ACID, M2_HOSTILE|M2_NEUTER, 0, CLR_GRAY), MON("brown pudding", S_PUDDING, - LVL(5, 3, 8, 0, 0), (G_GENO|1), + LVL(5, 3, 8, 0, 0), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_BITE, AD_DCAY, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, MS_SILENT, MZ_MEDIUM), @@ -1838,7 +1838,7 @@ struct permonst _mons2[] = { M1_MINDLESS|M1_OMNIVORE|M1_ACID, M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN), MON("green slime", S_PUDDING, - LVL(6, 6, 6, 0, 0), (G_HELL|G_GENO|1), + LVL(6, 6, 6, 0, 0), (G_HELL|G_GENO|G_NOCORPSE|1), A(ATTK(AT_TUCH, AD_SLIM, 1, 4), ATTK(AT_NONE, AD_SLIM, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 150, MS_SILENT, MZ_LARGE), @@ -1847,7 +1847,7 @@ struct permonst _mons2[] = { M1_MINDLESS|M1_OMNIVORE|M1_ACID|M1_POIS, M2_HOSTILE|M2_NEUTER, 0, CLR_GREEN), MON("black pudding", S_PUDDING, - LVL(10, 6, 6, 0, 0), (G_GENO|1), + LVL(10, 6, 6, 0, 0), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_BITE, AD_CORR, 3, 8), ATTK(AT_NONE, AD_CORR, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 250, MS_SILENT, MZ_LARGE), diff --git a/src/objnam.c b/src/objnam.c index bcd8c64b0..8b418d769 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -17,12 +17,12 @@ STATIC_DCL void FDECL(releaseobuf, (char *)); STATIC_DCL char *FDECL(minimal_xname, (struct obj *)); STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *)); STATIC_DCL boolean FDECL(singplur_lookup, (char *,char *,BOOLEAN_P, - const char *const *)); + const char *const *)); STATIC_DCL char *FDECL(singplur_compound, (char *)); struct Jitem { - int item; - const char *name; + int item; + const char *name; }; #define BSTRCMPI(base,ptr,str) ((ptr) < base || strcmpi((ptr),str)) @@ -31,26 +31,26 @@ struct Jitem { /* true for gems/rocks that should have " stone" appended to their names */ #define GemStone(typ) (typ == FLINT || \ - (objects[typ].oc_material == GEMSTONE && \ - (typ != DILITHIUM_CRYSTAL && typ != RUBY && \ - typ != DIAMOND && typ != SAPPHIRE && \ - typ != BLACK_OPAL && \ - typ != EMERALD && typ != OPAL))) + (objects[typ].oc_material == GEMSTONE && \ + (typ != DILITHIUM_CRYSTAL && typ != RUBY && \ + typ != DIAMOND && typ != SAPPHIRE && \ + typ != BLACK_OPAL && \ + typ != EMERALD && typ != OPAL))) STATIC_OVL struct Jitem Japanese_items[] = { - { SHORT_SWORD, "wakizashi" }, - { BROADSWORD, "ninja-to" }, - { FLAIL, "nunchaku" }, - { GLAIVE, "naginata" }, - { LOCK_PICK, "osaku" }, - { WOODEN_HARP, "koto" }, - { KNIFE, "shito" }, - { PLATE_MAIL, "tanko" }, - { HELMET, "kabuto" }, - { LEATHER_GLOVES, "yugake" }, - { FOOD_RATION, "gunyoki" }, - { POT_BOOZE, "sake" }, - {0, "" } + { SHORT_SWORD, "wakizashi" }, + { BROADSWORD, "ninja-to" }, + { FLAIL, "nunchaku" }, + { GLAIVE, "naginata" }, + { LOCK_PICK, "osaku" }, + { WOODEN_HARP, "koto" }, + { KNIFE, "shito" }, + { PLATE_MAIL, "tanko" }, + { HELMET, "kabuto" }, + { LEATHER_GLOVES, "yugake" }, + { FOOD_RATION, "gunyoki" }, + { POT_BOOZE, "sake" }, + {0, "" } }; STATIC_DCL const char *FDECL(Japanese_item_name,(int i)); @@ -60,15 +60,15 @@ strprepend(s,pref) register char *s; register const char *pref; { - register int i = (int)strlen(pref); - - if(i > PREFIX) { - impossible("PREFIX too short (for %d).", i); - return(s); - } - s -= i; - (void) strncpy(s, pref, i); /* do not copy trailing 0 */ - return(s); + register int i = (int)strlen(pref); + + if(i > PREFIX) { + impossible("PREFIX too short (for %d).", i); + return(s); + } + s -= i; + (void) strncpy(s, pref, i); /* do not copy trailing 0 */ + return(s); } /* manage a pool of BUFSZ buffers, so callers don't have to */ @@ -78,8 +78,8 @@ static int obufidx = 0; STATIC_OVL char * nextobuf() { - obufidx = (obufidx + 1) % NUMOBUF; - return obufs[obufidx]; + obufidx = (obufidx + 1) % NUMOBUF; + return obufs[obufidx]; } /* put the most recently allocated buffer back if possible */ @@ -87,85 +87,85 @@ STATIC_OVL void releaseobuf(bufp) char *bufp; { - /* caller may not know whether bufp is the most recently allocated - buffer; if it isn't, do nothing */ - if (bufp == obufs[obufidx]) - obufidx = (obufidx - 1 + NUMOBUF) % NUMOBUF; + /* caller may not know whether bufp is the most recently allocated + buffer; if it isn't, do nothing */ + if (bufp == obufs[obufidx]) + obufidx = (obufidx - 1 + NUMOBUF) % NUMOBUF; } char * obj_typename(otyp) register int otyp; { - char *buf = nextobuf(); - register struct objclass *ocl = &objects[otyp]; - register const char *actualn = OBJ_NAME(*ocl); - register const char *dn = OBJ_DESCR(*ocl); - register const char *un = ocl->oc_uname; - register int nn = ocl->oc_name_known; - - if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp)) - actualn = Japanese_item_name(otyp); - switch(ocl->oc_class) { - case COIN_CLASS: - Strcpy(buf, "coin"); - break; - case POTION_CLASS: - Strcpy(buf, "potion"); - break; - case SCROLL_CLASS: - Strcpy(buf, "scroll"); - break; - case WAND_CLASS: - Strcpy(buf, "wand"); - break; - case SPBOOK_CLASS: - Strcpy(buf, "spellbook"); - break; - case RING_CLASS: - Strcpy(buf, "ring"); - break; - case AMULET_CLASS: - if(nn) - Strcpy(buf,actualn); - else - Strcpy(buf,"amulet"); - if(un) - Sprintf(eos(buf)," called %s",un); - if(dn) - Sprintf(eos(buf)," (%s)",dn); - return(buf); - default: - if(nn) { - Strcpy(buf, actualn); - if (GemStone(otyp)) - Strcat(buf, " stone"); - if(un) - Sprintf(eos(buf), " called %s", un); - if(dn) - Sprintf(eos(buf), " (%s)", dn); - } else { - Strcpy(buf, dn ? dn : actualn); - if(ocl->oc_class == GEM_CLASS) - Strcat(buf, (ocl->oc_material == MINERAL) ? - " stone" : " gem"); - if(un) - Sprintf(eos(buf), " called %s", un); - } - return(buf); - } - /* here for ring/scroll/potion/wand */ - if(nn) { - if (ocl->oc_unique) - Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */ - else - Sprintf(eos(buf), " of %s", actualn); - } - if(un) - Sprintf(eos(buf), " called %s", un); - if(dn) - Sprintf(eos(buf), " (%s)", dn); - return(buf); + char *buf = nextobuf(); + register struct objclass *ocl = &objects[otyp]; + register const char *actualn = OBJ_NAME(*ocl); + register const char *dn = OBJ_DESCR(*ocl); + register const char *un = ocl->oc_uname; + register int nn = ocl->oc_name_known; + + if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp)) + actualn = Japanese_item_name(otyp); + switch(ocl->oc_class) { + case COIN_CLASS: + Strcpy(buf, "coin"); + break; + case POTION_CLASS: + Strcpy(buf, "potion"); + break; + case SCROLL_CLASS: + Strcpy(buf, "scroll"); + break; + case WAND_CLASS: + Strcpy(buf, "wand"); + break; + case SPBOOK_CLASS: + Strcpy(buf, "spellbook"); + break; + case RING_CLASS: + Strcpy(buf, "ring"); + break; + case AMULET_CLASS: + if(nn) + Strcpy(buf,actualn); + else + Strcpy(buf,"amulet"); + if(un) + Sprintf(eos(buf)," called %s",un); + if(dn) + Sprintf(eos(buf)," (%s)",dn); + return(buf); + default: + if(nn) { + Strcpy(buf, actualn); + if (GemStone(otyp)) + Strcat(buf, " stone"); + if(un) + Sprintf(eos(buf), " called %s", un); + if(dn) + Sprintf(eos(buf), " (%s)", dn); + } else { + Strcpy(buf, dn ? dn : actualn); + if(ocl->oc_class == GEM_CLASS) + Strcat(buf, (ocl->oc_material == MINERAL) ? + " stone" : " gem"); + if(un) + Sprintf(eos(buf), " called %s", un); + } + return(buf); + } + /* here for ring/scroll/potion/wand */ + if(nn) { + if (ocl->oc_unique) + Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */ + else + Sprintf(eos(buf), " of %s", actualn); + } + if(un) + Sprintf(eos(buf), " called %s", un); + if(dn) + Sprintf(eos(buf), " (%s)", dn); + return(buf); } /* less verbose result than obj_typename(); either the actual name @@ -180,7 +180,7 @@ int otyp; bufp = obj_typename(otyp); objects[otyp].oc_uname = save_uname; if ((pp = strstri(bufp, " (")) != 0) - *pp = '\0'; /* strip the appended description */ + *pp = '\0'; /* strip the appended description */ return bufp; } @@ -190,7 +190,7 @@ register struct obj *obj; { if (!obj->oartifact || !has_oname(obj)) return FALSE; if (!program_state.gameover && !iflags.override_ID) { - if (not_fully_identified(obj)) return FALSE; + if (not_fully_identified(obj)) return FALSE; } return TRUE; } @@ -208,13 +208,13 @@ distant_name(obj, func) register struct obj *obj; char *FDECL((*func), (OBJ_P)); { - char *str; + char *str; - long save_Blinded = Blinded; - Blinded = 1; - str = (*func)(obj); - Blinded = save_Blinded; - return str; + long save_Blinded = Blinded; + Blinded = 1; + str = (*func)(obj); + Blinded = save_Blinded; + return str; } /* convert player specified fruit name into corresponding fruit juice name @@ -227,9 +227,9 @@ boolean juice; /* whether or not to append " juice" to the name */ const char *fruit_nam = strstri(pl_fruit, " of "); if (fruit_nam) - fruit_nam += 4; /* skip past " of " */ + fruit_nam += 4; /* skip past " of " */ else - fruit_nam = pl_fruit; /* use it as is */ + fruit_nam = pl_fruit; /* use it as is */ Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : ""); return buf; @@ -239,140 +239,140 @@ char * xname(obj) register struct obj *obj; { - register char *buf; - register int typ = obj->otyp; - register struct objclass *ocl = &objects[typ]; - int nn = ocl->oc_name_known, omndx = obj->corpsenm; - const char *actualn = OBJ_NAME(*ocl); - const char *dn = OBJ_DESCR(*ocl); - const char *un = ocl->oc_uname; - boolean pluralize = (obj->quan != 1L); - boolean known, dknown, bknown; - - buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ - if (Role_if(PM_SAMURAI) && Japanese_item_name(typ)) - actualn = Japanese_item_name(typ); - - buf[0] = '\0'; - /* - * clean up known when it's tied to oc_name_known, eg after AD_DRIN - * This is only required for unique objects since the article - * printed for the object is tied to the combination of the two - * and printing the wrong article gives away information. - */ - if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0; - if (!Blind) obj->dknown = TRUE; - if (Role_if(PM_PRIEST)) obj->bknown = TRUE; - - if (iflags.override_ID) { - known = dknown = bknown = TRUE; - nn = 1; - } else { - known = obj->known; - dknown = obj->dknown; - bknown = obj->bknown; - } - - if (obj_is_pname(obj)) - goto nameit; - switch (obj->oclass) { - case AMULET_CLASS: - if (!dknown) - Strcpy(buf, "amulet"); - else if (typ == AMULET_OF_YENDOR || - typ == FAKE_AMULET_OF_YENDOR) - /* each must be identified individually */ - Strcpy(buf, known ? actualn : dn); - else if (nn) - Strcpy(buf, actualn); - else if (un) - Sprintf(buf,"amulet called %s", un); - else - Sprintf(buf,"%s amulet", dn); - break; - case WEAPON_CLASS: - if (is_poisonable(obj) && obj->opoisoned) - Strcpy(buf, "poisoned "); - case VENOM_CLASS: - case TOOL_CLASS: - if (typ == LENSES) - Strcpy(buf, "pair of "); - - if (!dknown) - Strcat(buf, dn ? dn : actualn); - else if (nn) - Strcat(buf, actualn); - else if (un) { - Strcat(buf, dn ? dn : actualn); - Strcat(buf, " called "); - Strcat(buf, un); - } else - Strcat(buf, dn ? dn : actualn); - /* If we use an() here we'd have to remember never to use */ - /* it whenever calling doname() or xname(). */ - if (typ == FIGURINE && omndx != NON_PM) - Sprintf(eos(buf), " of a%s %s", - index(vowels, *mons[omndx].mname) ? "n" : "", - mons[omndx].mname); - break; - case ARMOR_CLASS: - /* depends on order of the dragon scales objects */ - if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) { - Sprintf(buf, "set of %s", actualn); - break; - } - if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of "); - - if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD - && !dknown) { - Strcpy(buf, "shield"); - break; - } - if(obj->otyp == SHIELD_OF_REFLECTION && !dknown) { - Strcpy(buf, "smooth shield"); - break; - } - - if(nn) Strcat(buf, actualn); - else if(un) { - if(is_boots(obj)) - Strcat(buf,"boots"); - else if(is_gloves(obj)) - Strcat(buf,"gloves"); - else if(is_cloak(obj)) - Strcpy(buf,"cloak"); - else if(is_helmet(obj)) - Strcpy(buf,"helmet"); - else if(is_shield(obj)) - Strcpy(buf,"shield"); - else - Strcpy(buf,"armor"); - Strcat(buf, " called "); - Strcat(buf, un); - } else Strcat(buf, dn); - break; - case FOOD_CLASS: - if (typ == SLIME_MOLD) { - register struct fruit *f; - - for(f=ffruit; f; f = f->nextf) { - if(f->fid == obj->spe) { - Strcpy(buf, f->fname); - break; - } - } - if (!f) { - impossible("Bad fruit #%d?", obj->spe); - Strcpy(buf, "fruit"); - } else if (pluralize) { - /* ick; already pluralized fruit names - are allowed--we want to try to avoid - adding a redundant plural suffix */ - Strcpy(buf, makeplural(makesingular(buf))); - pluralize = FALSE; - } - break; - } + register char *buf; + register int typ = obj->otyp; + register struct objclass *ocl = &objects[typ]; + int nn = ocl->oc_name_known, omndx = obj->corpsenm; + const char *actualn = OBJ_NAME(*ocl); + const char *dn = OBJ_DESCR(*ocl); + const char *un = ocl->oc_uname; + boolean pluralize = (obj->quan != 1L); + boolean known, dknown, bknown; + + buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ + if (Role_if(PM_SAMURAI) && Japanese_item_name(typ)) + actualn = Japanese_item_name(typ); + + buf[0] = '\0'; + /* + * clean up known when it's tied to oc_name_known, eg after AD_DRIN + * This is only required for unique objects since the article + * printed for the object is tied to the combination of the two + * and printing the wrong article gives away information. + */ + if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0; + if (!Blind) obj->dknown = TRUE; + if (Role_if(PM_PRIEST)) obj->bknown = TRUE; + + if (iflags.override_ID) { + known = dknown = bknown = TRUE; + nn = 1; + } else { + known = obj->known; + dknown = obj->dknown; + bknown = obj->bknown; + } + + if (obj_is_pname(obj)) + goto nameit; + switch (obj->oclass) { + case AMULET_CLASS: + if (!dknown) + Strcpy(buf, "amulet"); + else if (typ == AMULET_OF_YENDOR || + typ == FAKE_AMULET_OF_YENDOR) + /* each must be identified individually */ + Strcpy(buf, known ? actualn : dn); + else if (nn) + Strcpy(buf, actualn); + else if (un) + Sprintf(buf,"amulet called %s", un); + else + Sprintf(buf,"%s amulet", dn); + break; + case WEAPON_CLASS: + if (is_poisonable(obj) && obj->opoisoned) + Strcpy(buf, "poisoned "); + case VENOM_CLASS: + case TOOL_CLASS: + if (typ == LENSES) + Strcpy(buf, "pair of "); + + if (!dknown) + Strcat(buf, dn ? dn : actualn); + else if (nn) + Strcat(buf, actualn); + else if (un) { + Strcat(buf, dn ? dn : actualn); + Strcat(buf, " called "); + Strcat(buf, un); + } else + Strcat(buf, dn ? dn : actualn); + /* If we use an() here we'd have to remember never to use */ + /* it whenever calling doname() or xname(). */ + if (typ == FIGURINE && omndx != NON_PM) + Sprintf(eos(buf), " of a%s %s", + index(vowels, *mons[omndx].mname) ? "n" : "", + mons[omndx].mname); + break; + case ARMOR_CLASS: + /* depends on order of the dragon scales objects */ + if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) { + Sprintf(buf, "set of %s", actualn); + break; + } + if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of "); + + if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD + && !dknown) { + Strcpy(buf, "shield"); + break; + } + if(obj->otyp == SHIELD_OF_REFLECTION && !dknown) { + Strcpy(buf, "smooth shield"); + break; + } + + if(nn) Strcat(buf, actualn); + else if(un) { + if(is_boots(obj)) + Strcat(buf,"boots"); + else if(is_gloves(obj)) + Strcat(buf,"gloves"); + else if(is_cloak(obj)) + Strcpy(buf,"cloak"); + else if(is_helmet(obj)) + Strcpy(buf,"helmet"); + else if(is_shield(obj)) + Strcpy(buf,"shield"); + else + Strcpy(buf,"armor"); + Strcat(buf, " called "); + Strcat(buf, un); + } else Strcat(buf, dn); + break; + case FOOD_CLASS: + if (typ == SLIME_MOLD) { + register struct fruit *f; + + for(f=ffruit; f; f = f->nextf) { + if(f->fid == obj->spe) { + Strcpy(buf, f->fname); + break; + } + } + if (!f) { + impossible("Bad fruit #%d?", obj->spe); + Strcpy(buf, "fruit"); + } else if (pluralize) { + /* ick; already pluralized fruit names + are allowed--we want to try to avoid + adding a redundant plural suffix */ + Strcpy(buf, makeplural(makesingular(buf))); + pluralize = FALSE; + } + break; + } if (Is_pudding(obj)) { Sprintf(buf, "%s%s", obj->owt < 100 ? "small " @@ -382,136 +382,136 @@ register struct obj *obj; break; } - Strcpy(buf, actualn); - if (typ == TIN && known) - tin_details(obj, omndx, buf); - break; - case COIN_CLASS: - case CHAIN_CLASS: - Strcpy(buf, actualn); - break; - case ROCK_CLASS: - if (typ == STATUE && omndx != NON_PM) - Sprintf(buf, "%s%s of %s%s", - (Role_if(PM_ARCHEOLOGIST) && - (obj->spe & STATUE_HISTORIC)) ? "historic " : "", - actualn, - type_is_pname(&mons[omndx]) ? "" : - the_unique_pm(&mons[omndx]) ? "the " : - index(vowels, *mons[omndx].mname) ? "an " : "a ", - mons[omndx].mname); - else Strcpy(buf, actualn); - break; - case BALL_CLASS: - Sprintf(buf, "%sheavy iron ball", - (obj->owt > ocl->oc_weight) ? "very " : ""); - break; - case POTION_CLASS: - if (dknown && obj->odiluted) - Strcpy(buf, "diluted "); - if(nn || un || !dknown) { - Strcat(buf, "potion"); - if(!dknown) break; - if(nn) { - Strcat(buf, " of "); - if (typ == POT_WATER && - bknown && (obj->blessed || obj->cursed)) { - Strcat(buf, obj->blessed ? "holy " : "unholy "); - } - Strcat(buf, actualn); - } else { - Strcat(buf, " called "); - Strcat(buf, un); - } - } else { - Strcat(buf, dn); - Strcat(buf, " potion"); - } - break; - case SCROLL_CLASS: - Strcpy(buf, "scroll"); - if(!dknown) break; - if(nn) { - Strcat(buf, " of "); - Strcat(buf, actualn); - } else if(un) { - Strcat(buf, " called "); - Strcat(buf, un); - } else if (ocl->oc_magic) { - Strcat(buf, " labeled "); - Strcat(buf, dn); - } else { - Strcpy(buf, dn); - Strcat(buf, " scroll"); - } - break; - case WAND_CLASS: - if(!dknown) - Strcpy(buf, "wand"); - else if(nn) - Sprintf(buf, "wand of %s", actualn); - else if(un) - Sprintf(buf, "wand called %s", un); - else - Sprintf(buf, "%s wand", dn); - break; - case SPBOOK_CLASS: - if (!dknown) { - Strcpy(buf, "spellbook"); - } else if (nn) { - if (typ != SPE_BOOK_OF_THE_DEAD) - Strcpy(buf, "spellbook of "); - Strcat(buf, actualn); - } else if (un) { - Sprintf(buf, "spellbook called %s", un); - } else - Sprintf(buf, "%s spellbook", dn); - break; - case RING_CLASS: - if(!dknown) - Strcpy(buf, "ring"); - else if(nn) - Sprintf(buf, "ring of %s", actualn); - else if(un) - Sprintf(buf, "ring called %s", un); - else - Sprintf(buf, "%s ring", dn); - break; - case GEM_CLASS: - { - const char *rock = - (ocl->oc_material == MINERAL) ? "stone" : "gem"; - if (!dknown) { - Strcpy(buf, rock); - } else if (!nn) { - if (un) Sprintf(buf,"%s called %s", rock, un); - else Sprintf(buf, "%s %s", dn, rock); - } else { - Strcpy(buf, actualn); - if (GemStone(typ)) Strcat(buf, " stone"); - } - break; - } - default: - Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe); - } - if (pluralize) Strcpy(buf, makeplural(buf)); - - if (has_oname(obj) && dknown) { - Strcat(buf, " named "); + Strcpy(buf, actualn); + if (typ == TIN && known) + tin_details(obj, omndx, buf); + break; + case COIN_CLASS: + case CHAIN_CLASS: + Strcpy(buf, actualn); + break; + case ROCK_CLASS: + if (typ == STATUE && omndx != NON_PM) + Sprintf(buf, "%s%s of %s%s", + (Role_if(PM_ARCHEOLOGIST) && + (obj->spe & STATUE_HISTORIC)) ? "historic " : "", + actualn, + type_is_pname(&mons[omndx]) ? "" : + the_unique_pm(&mons[omndx]) ? "the " : + index(vowels, *mons[omndx].mname) ? "an " : "a ", + mons[omndx].mname); + else Strcpy(buf, actualn); + break; + case BALL_CLASS: + Sprintf(buf, "%sheavy iron ball", + (obj->owt > ocl->oc_weight) ? "very " : ""); + break; + case POTION_CLASS: + if (dknown && obj->odiluted) + Strcpy(buf, "diluted "); + if(nn || un || !dknown) { + Strcat(buf, "potion"); + if(!dknown) break; + if(nn) { + Strcat(buf, " of "); + if (typ == POT_WATER && + bknown && (obj->blessed || obj->cursed)) { + Strcat(buf, obj->blessed ? "holy " : "unholy "); + } + Strcat(buf, actualn); + } else { + Strcat(buf, " called "); + Strcat(buf, un); + } + } else { + Strcat(buf, dn); + Strcat(buf, " potion"); + } + break; + case SCROLL_CLASS: + Strcpy(buf, "scroll"); + if(!dknown) break; + if(nn) { + Strcat(buf, " of "); + Strcat(buf, actualn); + } else if(un) { + Strcat(buf, " called "); + Strcat(buf, un); + } else if (ocl->oc_magic) { + Strcat(buf, " labeled "); + Strcat(buf, dn); + } else { + Strcpy(buf, dn); + Strcat(buf, " scroll"); + } + break; + case WAND_CLASS: + if(!dknown) + Strcpy(buf, "wand"); + else if(nn) + Sprintf(buf, "wand of %s", actualn); + else if(un) + Sprintf(buf, "wand called %s", un); + else + Sprintf(buf, "%s wand", dn); + break; + case SPBOOK_CLASS: + if (!dknown) { + Strcpy(buf, "spellbook"); + } else if (nn) { + if (typ != SPE_BOOK_OF_THE_DEAD) + Strcpy(buf, "spellbook of "); + Strcat(buf, actualn); + } else if (un) { + Sprintf(buf, "spellbook called %s", un); + } else + Sprintf(buf, "%s spellbook", dn); + break; + case RING_CLASS: + if(!dknown) + Strcpy(buf, "ring"); + else if(nn) + Sprintf(buf, "ring of %s", actualn); + else if(un) + Sprintf(buf, "ring called %s", un); + else + Sprintf(buf, "%s ring", dn); + break; + case GEM_CLASS: + { + const char *rock = + (ocl->oc_material == MINERAL) ? "stone" : "gem"; + if (!dknown) { + Strcpy(buf, rock); + } else if (!nn) { + if (un) Sprintf(buf,"%s called %s", rock, un); + else Sprintf(buf, "%s %s", dn, rock); + } else { + Strcpy(buf, actualn); + if (GemStone(typ)) Strcat(buf, " stone"); + } + break; + } + default: + Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe); + } + if (pluralize) Strcpy(buf, makeplural(buf)); + + if (has_oname(obj) && dknown) { + Strcat(buf, " named "); nameit: - Strcat(buf, ONAME(obj)); - } + Strcat(buf, ONAME(obj)); + } - if (!strncmpi(buf, "the ", 4)) buf += 4; - return(buf); + if (!strncmpi(buf, "the ", 4)) buf += 4; + return(buf); } /* similar to simple_typename but minimal_xname operates on a particular object rather than its general type; it formats the most basic info: - potion -- if description not known - brown potion -- if oc_name_known not set - potion of object detection -- if discovered + potion -- if description not known + brown potion -- if oc_name_known not set + potion of object detection -- if discovered */ static char * minimal_xname(obj) @@ -537,8 +537,8 @@ struct obj *obj; bareobj.dknown = obj->dknown; /* suppress known except for amulets (needed for fakes and real A-of-Y) */ bareobj.known = (obj->oclass == AMULET_CLASS) ? obj->known : - /* default is "on" for types which don't use it */ - !objects[otyp].oc_uses_known; + /* default is "on" for types which don't use it */ + !objects[otyp].oc_uses_known; bareobj.quan = 1L; /* don't want plural */ bareobj.corpsenm = NON_PM; /* suppress statue and figurine details */ bufp = distant_name(&bareobj, xname); /* xname(&bareobj) */ @@ -558,11 +558,11 @@ struct obj *obj; char *onm = xname(obj); if (m_shot.n > 1 && m_shot.o == obj->otyp) { - /* copy xname's result so that we can reuse its return buffer */ - Strcpy(tmpbuf, onm); - /* "the Nth arrow"; value will eventually be passed to an() or - The(), both of which correctly handle this "the " prefix */ - Sprintf(onm, "the %d%s %s", m_shot.i, ordin(m_shot.i), tmpbuf); + /* copy xname's result so that we can reuse its return buffer */ + Strcpy(tmpbuf, onm); + /* "the Nth arrow"; value will eventually be passed to an() or + The(), both of which correctly handle this "the " prefix */ + Sprintf(onm, "the %d%s %s", m_shot.i, ordin(m_shot.i), tmpbuf); } return onm; @@ -576,12 +576,12 @@ register struct obj *obj; { boolean known = (obj->known || iflags.override_ID); if (!obj->dknown && !iflags.override_ID) - return FALSE; + return FALSE; else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !known) - return TRUE; /* lie */ + return TRUE; /* lie */ else - return (boolean)(objects[obj->otyp].oc_unique && - (known || obj->otyp == AMULET_OF_YENDOR)); + return (boolean)(objects[obj->otyp].oc_unique && + (known || obj->otyp == AMULET_OF_YENDOR)); } /* should monster type be prefixed with "the"? (mostly used for corpses) */ @@ -589,22 +589,22 @@ boolean the_unique_pm(ptr) struct permonst *ptr; { - boolean uniq; - - /* even though monsters with personal names are unique, we want to - describe them as "Name" rather than "the Name" */ - if (type_is_pname(ptr)) return FALSE; - - uniq = (ptr->geno & G_UNIQ) ? TRUE : FALSE; - /* high priest is unique if it includes "of ", otherwise not - (caller needs to handle the 1st possibility; we assume the 2nd); - worm tail should be irrelevant but is included for completeness */ - if (ptr == &mons[PM_HIGH_PRIEST] || ptr == &mons[PM_LONG_WORM_TAIL]) - uniq = FALSE; - /* Wizard no longer needs this; he's flagged as unique these days */ - if (ptr == &mons[PM_WIZARD_OF_YENDOR]) - uniq = TRUE; - return uniq; + boolean uniq; + + /* even though monsters with personal names are unique, we want to + describe them as "Name" rather than "the Name" */ + if (type_is_pname(ptr)) return FALSE; + + uniq = (ptr->geno & G_UNIQ) ? TRUE : FALSE; + /* high priest is unique if it includes "of ", otherwise not + (caller needs to handle the 1st possibility; we assume the 2nd); + worm tail should be irrelevant but is included for completeness */ + if (ptr == &mons[PM_HIGH_PRIEST] || ptr == &mons[PM_LONG_WORM_TAIL]) + uniq = FALSE; + /* Wizard no longer needs this; he's flagged as unique these days */ + if (ptr == &mons[PM_WIZARD_OF_YENDOR]) + uniq = TRUE; + return uniq; } STATIC_OVL void @@ -612,321 +612,324 @@ add_erosion_words(obj,prefix) struct obj *obj; char *prefix; { - boolean iscrys = (obj->otyp == CRYSKNIFE); - boolean rknown; - - rknown = (iflags.override_ID == 0) ? obj->rknown : TRUE; - - if (!is_damageable(obj) && !iscrys) return; - - /* The only cases where any of these bits do double duty are for - * rotted food and diluted potions, which are all not is_damageable(). - */ - if (obj->oeroded && !iscrys) { - switch (obj->oeroded) { - case 2: Strcat(prefix, "very "); break; - case 3: Strcat(prefix, "thoroughly "); break; - } - Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt "); - } - if (obj->oeroded2 && !iscrys) { - switch (obj->oeroded2) { - case 2: Strcat(prefix, "very "); break; - case 3: Strcat(prefix, "thoroughly "); break; - } - Strcat(prefix, is_corrodeable(obj) ? "corroded " : - "rotted "); - } - if (rknown && obj->oerodeproof) - Strcat(prefix, - iscrys ? "fixed " : - is_rustprone(obj) ? "rustproof " : - is_corrodeable(obj) ? "corrodeproof " : /* "stainless"? */ - is_flammable(obj) ? "fireproof " : ""); + boolean iscrys = (obj->otyp == CRYSKNIFE); + boolean rknown; + + rknown = (iflags.override_ID == 0) ? obj->rknown : TRUE; + + if (!is_damageable(obj) && !iscrys) return; + + /* The only cases where any of these bits do double duty are for + * rotted food and diluted potions, which are all not is_damageable(). + */ + if (obj->oeroded && !iscrys) { + switch (obj->oeroded) { + case 2: Strcat(prefix, "very "); break; + case 3: Strcat(prefix, "thoroughly "); break; + } + Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt "); + } + if (obj->oeroded2 && !iscrys) { + switch (obj->oeroded2) { + case 2: Strcat(prefix, "very "); break; + case 3: Strcat(prefix, "thoroughly "); break; + } + Strcat(prefix, is_corrodeable(obj) ? "corroded " : + "rotted "); + } + if (rknown && obj->oerodeproof) + Strcat(prefix, + iscrys ? "fixed " : + is_rustprone(obj) ? "rustproof " : + is_corrodeable(obj) ? "corrodeproof " : /* "stainless"? */ + is_flammable(obj) ? "fireproof " : ""); } char * doname(obj) register struct obj *obj; { - boolean ispoisoned = FALSE; - boolean known, cknown, bknown, lknown; - int omndx = obj->corpsenm; - char prefix[PREFIX]; - char tmpbuf[PREFIX+1]; - /* when we have to add something at the start of prefix instead of the - * end (Strcat is used on the end) - */ - register char *bp = xname(obj); - - if (iflags.override_ID) known = cknown = bknown = lknown = TRUE; - else { - known = obj->known; - cknown = obj->cknown; - bknown = obj->bknown; - lknown = obj->lknown; - } - - /* When using xname, we want "poisoned arrow", and when using - * doname, we want "poisoned +0 arrow". This kludge is about the only - * way to do it, at least until someone overhauls xname() and doname(), - * combining both into one function taking a parameter. - */ - /* must check opoisoned--someone can have a weirdly-named fruit */ - if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) { - bp += 9; - ispoisoned = TRUE; - } - - if(obj->quan != 1L) - Sprintf(prefix, "%ld ", obj->quan); - else if (obj->otyp == CORPSE) - /* skip article prefix for corpses [else corpse_xname() - would have to be taught how to strip it off again] */ - *prefix = '\0'; - else if (obj_is_pname(obj) || the_unique_obj(obj)) { - if (!strncmpi(bp, "the ", 4)) - bp += 4; - Strcpy(prefix, "the "); - } else - Strcpy(prefix, "a "); - - /* "empty" goes at the beginning, but item count goes at the end */ - if (cknown && - (Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj)) - Strcat(prefix, "empty "); - - if (bknown && - obj->oclass != COIN_CLASS && - (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known - || (!obj->cursed && !obj->blessed))) { - /* allow 'blessed clear potion' if we don't know it's holy water; - * always allow "uncursed potion of water" - */ - if (obj->cursed) - Strcat(prefix, "cursed "); - else if (obj->blessed) - Strcat(prefix, "blessed "); - else if ((!known || !objects[obj->otyp].oc_charged || - (obj->oclass == ARMOR_CLASS || - obj->oclass == RING_CLASS)) - /* For most items with charges or +/-, if you know how many - * charges are left or what the +/- is, then you must have - * totally identified the item, so "uncursed" is unneccesary, - * because an identified object not described as "blessed" or - * "cursed" must be uncursed. - * - * If the charges or +/- is not known, "uncursed" must be - * printed to avoid ambiguity between an item whose curse - * status is unknown, and an item known to be uncursed. - */ + boolean ispoisoned = FALSE; + boolean known, cknown, bknown, lknown; + int omndx = obj->corpsenm; + char prefix[PREFIX]; + char tmpbuf[PREFIX+1]; + /* when we have to add something at the start of prefix instead of the + * end (Strcat is used on the end) + */ + register char *bp = xname(obj); + + if (iflags.override_ID) known = cknown = bknown = lknown = TRUE; + else { + known = obj->known; + cknown = obj->cknown; + bknown = obj->bknown; + lknown = obj->lknown; + } + + /* When using xname, we want "poisoned arrow", and when using + * doname, we want "poisoned +0 arrow". This kludge is about the only + * way to do it, at least until someone overhauls xname() and doname(), + * combining both into one function taking a parameter. + */ + /* must check opoisoned--someone can have a weirdly-named fruit */ + if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) { + bp += 9; + ispoisoned = TRUE; + } + + if(obj->quan != 1L) + Sprintf(prefix, "%ld ", obj->quan); + else if (obj->otyp == CORPSE) + /* skip article prefix for corpses [else corpse_xname() + would have to be taught how to strip it off again] */ + *prefix = '\0'; + else if (obj_is_pname(obj) || the_unique_obj(obj)) { + if (!strncmpi(bp, "the ", 4)) + bp += 4; + Strcpy(prefix, "the "); + } else + Strcpy(prefix, "a "); + + /* "empty" goes at the beginning, but item count goes at the end */ + if (cknown && + (Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj)) + Strcat(prefix, "empty "); + + if (bknown && + obj->oclass != COIN_CLASS && + (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known + || (!obj->cursed && !obj->blessed))) { + /* allow 'blessed clear potion' if we don't know it's holy water; + * always allow "uncursed potion of water" + */ + if (obj->cursed) + Strcat(prefix, "cursed "); + else if (obj->blessed) + Strcat(prefix, "blessed "); + else if ((!known || !objects[obj->otyp].oc_charged || + (obj->oclass == ARMOR_CLASS || + obj->oclass == RING_CLASS)) + /* For most items with charges or +/-, if you know how many + * charges are left or what the +/- is, then you must have + * totally identified the item, so "uncursed" is unneccesary, + * because an identified object not described as "blessed" or + * "cursed" must be uncursed. + * + * If the charges or +/- is not known, "uncursed" must be + * printed to avoid ambiguity between an item whose curse + * status is unknown, and an item known to be uncursed. + */ #ifdef MAIL - && obj->otyp != SCR_MAIL + && obj->otyp != SCR_MAIL #endif - && obj->otyp != FAKE_AMULET_OF_YENDOR - && obj->otyp != AMULET_OF_YENDOR - && !Role_if(PM_PRIEST)) - Strcat(prefix, "uncursed "); - } - - if (lknown && Is_box(obj)) { - if (obj->obroken) - Strcat(prefix, "unlockable "); - else if (obj->olocked) - Strcat(prefix, "locked "); - else - Strcat(prefix, "unlocked "); - } - - if (obj->greased) Strcat(prefix, "greased "); - - if (cknown && Has_contents(obj)) { - /* we count all objects (obj->quantity); perhaps we should - count seperate stacks instead (or even introduce a user - preference option to choose between the two alternatives) - since it's somewhat odd so see "containing 1002 items" - when there are 2 scrolls plus 1000 gold pieces */ - long itemcount = count_contents(obj, FALSE, TRUE, TRUE); - - Sprintf(eos(bp), " containing %ld item%s", - itemcount, plur(itemcount)); - } - - switch(obj->oclass) { - case AMULET_CLASS: - if(obj->owornmask & W_AMUL) - Strcat(bp, " (being worn)"); - break; - case WEAPON_CLASS: - if(ispoisoned) - Strcat(prefix, "poisoned "); + && obj->otyp != FAKE_AMULET_OF_YENDOR + && obj->otyp != AMULET_OF_YENDOR + && !Role_if(PM_PRIEST)) + Strcat(prefix, "uncursed "); + } + + if (lknown && Is_box(obj)) { + if (obj->obroken) + Strcat(prefix, "unlockable "); + else if (obj->olocked) + Strcat(prefix, "locked "); + else + Strcat(prefix, "unlocked "); + } + + if (obj->greased) Strcat(prefix, "greased "); + + if (cknown && Has_contents(obj)) { + /* we count all objects (obj->quantity); perhaps we should + count seperate stacks instead (or even introduce a user + preference option to choose between the two alternatives) + since it's somewhat odd so see "containing 1002 items" + when there are 2 scrolls plus 1000 gold pieces */ + long itemcount = count_contents(obj, FALSE, TRUE, TRUE); + + Sprintf(eos(bp), " containing %ld item%s", + itemcount, plur(itemcount)); + } + + switch(obj->oclass) { + case AMULET_CLASS: + if(obj->owornmask & W_AMUL) + Strcat(bp, " (being worn)"); + break; + case WEAPON_CLASS: + if(ispoisoned) + Strcat(prefix, "poisoned "); plus: - add_erosion_words(obj, prefix); - if(known) { - Strcat(prefix, sitoa(obj->spe)); - Strcat(prefix, " "); - } - break; - case ARMOR_CLASS: - if(obj->owornmask & W_ARMOR) - Strcat(bp, (obj == uskin) ? " (embedded in your skin)" : - " (being worn)"); - goto plus; - case TOOL_CLASS: - /* weptools already get this done when we go to the +n code */ - if (!is_weptool(obj)) - add_erosion_words(obj, prefix); - if(obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) { - Strcat(bp, " (being worn)"); - break; - } - if (obj->otyp == LEASH && obj->leashmon != 0) { - Strcat(bp, " (in use)"); - break; - } - if (is_weptool(obj)) - goto plus; - if (obj->otyp == CANDELABRUM_OF_INVOCATION) { - if (!obj->spe) - Strcpy(tmpbuf, "no"); - else - Sprintf(tmpbuf, "%d", obj->spe); - Sprintf(eos(bp), " (%s candle%s%s)", - tmpbuf, plur(obj->spe), - !obj->lamplit ? " attached" : ", lit"); - break; - } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || - obj->otyp == BRASS_LANTERN || Is_candle(obj)) { - if (Is_candle(obj) && - obj->age < 20L * (long)objects[obj->otyp].oc_cost) - Strcat(prefix, "partly used "); - if(obj->lamplit) - Strcat(bp, " (lit)"); - break; - } - if(objects[obj->otyp].oc_charged) - goto charges; - break; - case WAND_CLASS: - add_erosion_words(obj, prefix); + add_erosion_words(obj, prefix); + if(known) { + Strcat(prefix, sitoa(obj->spe)); + Strcat(prefix, " "); + } + break; + case ARMOR_CLASS: + if(obj->owornmask & W_ARMOR) + Strcat(bp, (obj == uskin) ? " (embedded in your skin)" : + " (being worn)"); + goto plus; + case TOOL_CLASS: + /* weptools already get this done when we go to the +n code */ + if (!is_weptool(obj)) + add_erosion_words(obj, prefix); + if(obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) { + Strcat(bp, " (being worn)"); + break; + } + if (obj->otyp == LEASH && obj->leashmon != 0) { + Strcat(bp, " (in use)"); + break; + } + if (is_weptool(obj)) + goto plus; + if (obj->otyp == CANDELABRUM_OF_INVOCATION) { + if (!obj->spe) + Strcpy(tmpbuf, "no"); + else + Sprintf(tmpbuf, "%d", obj->spe); + Sprintf(eos(bp), " (%s candle%s%s)", + tmpbuf, plur(obj->spe), + !obj->lamplit ? " attached" : ", lit"); + break; + } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || + obj->otyp == BRASS_LANTERN || Is_candle(obj)) { + if (Is_candle(obj) && + obj->age < 20L * (long)objects[obj->otyp].oc_cost) + Strcat(prefix, "partly used "); + if(obj->lamplit) + Strcat(bp, " (lit)"); + break; + } + if(objects[obj->otyp].oc_charged) + goto charges; + break; + case WAND_CLASS: + add_erosion_words(obj, prefix); charges: - if(known) - Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe); - break; - case POTION_CLASS: - if (obj->otyp == POT_OIL && obj->lamplit) - Strcat(bp, " (lit)"); - break; - case RING_CLASS: - add_erosion_words(obj, prefix); + if(known) + Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe); + break; + case POTION_CLASS: + if (obj->otyp == POT_OIL && obj->lamplit) + Strcat(bp, " (lit)"); + break; + case RING_CLASS: + add_erosion_words(obj, prefix); ring: - if(obj->owornmask & W_RINGR) Strcat(bp, " (on right "); - if(obj->owornmask & W_RINGL) Strcat(bp, " (on left "); - if(obj->owornmask & W_RING) { - Strcat(bp, body_part(HAND)); - Strcat(bp, ")"); - } - if(known && objects[obj->otyp].oc_charged) { - Strcat(prefix, sitoa(obj->spe)); - Strcat(prefix, " "); - } - break; - case FOOD_CLASS: - if (obj->oeaten) - Strcat(prefix, "partly eaten "); - if (obj->otyp == CORPSE) { - Sprintf(prefix, "%s ", - corpse_xname(obj, prefix, - CXN_ARTICLE|CXN_NOCORPSE)); - } else if (obj->otyp == EGG) { + if(obj->owornmask & W_RINGR) Strcat(bp, " (on right "); + if(obj->owornmask & W_RINGL) Strcat(bp, " (on left "); + if(obj->owornmask & W_RING) { + Strcat(bp, body_part(HAND)); + Strcat(bp, ")"); + } + if(known && objects[obj->otyp].oc_charged) { + Strcat(prefix, sitoa(obj->spe)); + Strcat(prefix, " "); + } + break; + case FOOD_CLASS: + if (obj->oeaten) + Strcat(prefix, "partly eaten "); + if (obj->otyp == CORPSE) { + Sprintf(prefix, "%s ", + corpse_xname(obj, prefix, + CXN_ARTICLE|CXN_NOCORPSE)); + } else if (obj->otyp == EGG) { #if 0 /* corpses don't tell if they're stale either */ - if (known && stale_egg(obj)) - Strcat(prefix, "stale "); + if (known && stale_egg(obj)) + Strcat(prefix, "stale "); #endif - if (omndx >= LOW_PM && (known || - (mvitals[omndx].mvflags & MV_KNOWS_EGG))) { - Strcat(prefix, mons[omndx].mname); - Strcat(prefix, " "); - if (obj->spe) - Strcat(bp, " (laid by you)"); - } - } - if (obj->otyp == MEAT_RING) goto ring; - break; - case BALL_CLASS: - case CHAIN_CLASS: - add_erosion_words(obj, prefix); - if(obj->owornmask & W_BALL) - Strcat(bp, " (chained to you)"); - break; - } - - if((obj->owornmask & W_WEP) && !mrg_to_wielded) { - if (obj->quan != 1L) { - Strcat(bp, " (wielded)"); - } else { - const char *hand_s = body_part(HAND); - - if (bimanual(obj)) hand_s = makeplural(hand_s); - Sprintf(eos(bp), " (weapon in %s)", hand_s); - } - } - if(obj->owornmask & W_SWAPWEP) { - if (u.twoweap) - Sprintf(eos(bp), " (wielded in other %s)", - body_part(HAND)); - else - Strcat(bp, " (alternate weapon; not wielded)"); - } - if(obj->owornmask & W_QUIVER){ - switch(obj->oclass){ - case WEAPON_CLASS: - if(is_ammo(obj)){ - if(objects[obj->otyp].oc_skill == -P_BOW){ - /* Ammo for a bow */ - Strcat(bp, " (in quiver)"); - break; - } else { - /* Ammo not for a bow */ - Strcat(bp, " (in quiver pouch)"); - break; - } - } else { - /* Weapons not considered ammo */ - Strcat(bp, " (at the ready)"); - break; - } - - /* Small things and ammo not for a bow */ - case RING_CLASS: - case AMULET_CLASS: - case WAND_CLASS: - case COIN_CLASS: - case GEM_CLASS: - Strcat(bp, " (in quiver pouch)"); - break; - default: /* odd things */ - Strcat(bp, " (at the ready)"); - } - } - if (!iflags.suppress_price && is_unpaid(obj)) { - long quotedprice = unpaid_cost(obj, TRUE); - - Sprintf(eos(bp), " (%s, %ld %s)", - obj->unpaid ? "unpaid" : "contents", - quotedprice, currency(quotedprice)); - } - if (!strncmp(prefix, "a ", 2) && - index(vowels, *(prefix+2) ? *(prefix+2) : *bp) - && (*(prefix+2) || (strncmp(bp, "uranium", 7) - && strncmp(bp, "unicorn", 7) - && strncmp(bp, "eucalyptus", 10)))) { - Strcpy(tmpbuf, prefix); - Strcpy(prefix, "an "); - Strcpy(prefix+3, tmpbuf+2); - } - bp = strprepend(bp, prefix); - return(bp); + if (omndx >= LOW_PM && (known || + (mvitals[omndx].mvflags & MV_KNOWS_EGG))) { + Strcat(prefix, mons[omndx].mname); + Strcat(prefix, " "); + if (obj->spe) + Strcat(bp, " (laid by you)"); + } + } + if (wizard) { + Sprintf(eos(bp), " (%d aum)", obj->owt); + } + if (obj->otyp == MEAT_RING) goto ring; + break; + case BALL_CLASS: + case CHAIN_CLASS: + add_erosion_words(obj, prefix); + if(obj->owornmask & W_BALL) + Strcat(bp, " (chained to you)"); + break; + } + + if((obj->owornmask & W_WEP) && !mrg_to_wielded) { + if (obj->quan != 1L) { + Strcat(bp, " (wielded)"); + } else { + const char *hand_s = body_part(HAND); + + if (bimanual(obj)) hand_s = makeplural(hand_s); + Sprintf(eos(bp), " (weapon in %s)", hand_s); + } + } + if(obj->owornmask & W_SWAPWEP) { + if (u.twoweap) + Sprintf(eos(bp), " (wielded in other %s)", + body_part(HAND)); + else + Strcat(bp, " (alternate weapon; not wielded)"); + } + if(obj->owornmask & W_QUIVER){ + switch(obj->oclass){ + case WEAPON_CLASS: + if(is_ammo(obj)){ + if(objects[obj->otyp].oc_skill == -P_BOW){ + /* Ammo for a bow */ + Strcat(bp, " (in quiver)"); + break; + } else { + /* Ammo not for a bow */ + Strcat(bp, " (in quiver pouch)"); + break; + } + } else { + /* Weapons not considered ammo */ + Strcat(bp, " (at the ready)"); + break; + } + + /* Small things and ammo not for a bow */ + case RING_CLASS: + case AMULET_CLASS: + case WAND_CLASS: + case COIN_CLASS: + case GEM_CLASS: + Strcat(bp, " (in quiver pouch)"); + break; + default: /* odd things */ + Strcat(bp, " (at the ready)"); + } + } + if (!iflags.suppress_price && is_unpaid(obj)) { + long quotedprice = unpaid_cost(obj, TRUE); + + Sprintf(eos(bp), " (%s, %ld %s)", + obj->unpaid ? "unpaid" : "contents", + quotedprice, currency(quotedprice)); + } + if (!strncmp(prefix, "a ", 2) && + index(vowels, *(prefix+2) ? *(prefix+2) : *bp) + && (*(prefix+2) || (strncmp(bp, "uranium", 7) + && strncmp(bp, "unicorn", 7) + && strncmp(bp, "eucalyptus", 10)))) { + Strcpy(tmpbuf, prefix); + Strcpy(prefix, "an "); + Strcpy(prefix+3, tmpbuf+2); + } + bp = strprepend(bp, prefix); + return(bp); } /* used from invent.c */ @@ -939,32 +942,32 @@ register struct obj *otmp; /* check fundamental ID hallmarks first */ if (!otmp->known || !otmp->dknown || #ifdef MAIL - (!otmp->bknown && otmp->otyp != SCR_MAIL) || + (!otmp->bknown && otmp->otyp != SCR_MAIL) || #else - !otmp->bknown || + !otmp->bknown || #endif - !objects[otmp->otyp].oc_name_known) - return TRUE; + !objects[otmp->otyp].oc_name_known) + return TRUE; if ((!otmp->cknown && (Is_container(otmp) || otmp->otyp == STATUE)) || - (!otmp->lknown && Is_box(otmp))) - return TRUE; + (!otmp->lknown && Is_box(otmp))) + return TRUE; if (otmp->oartifact && undiscovered_artifact(otmp->oartifact)) - return TRUE; + return TRUE; /* otmp->rknown is the only item of interest if we reach here */ /* - * Note: if a revision ever allows scrolls to become fireproof or - * rings to become shockproof, this checking will need to be revised. - * `rknown' ID only matters if xname() will provide the info about it. - */ + * Note: if a revision ever allows scrolls to become fireproof or + * rings to become shockproof, this checking will need to be revised. + * `rknown' ID only matters if xname() will provide the info about it. + */ if (otmp->rknown || (otmp->oclass != ARMOR_CLASS && - otmp->oclass != WEAPON_CLASS && - !is_weptool(otmp) && /* (redunant) */ - otmp->oclass != BALL_CLASS)) /* (useless) */ - return FALSE; + otmp->oclass != WEAPON_CLASS && + !is_weptool(otmp) && /* (redunant) */ + otmp->oclass != BALL_CLASS)) /* (useless) */ + return FALSE; else /* lack of `rknown' only matters for vulnerable objects */ - return (boolean)(is_rustprone(otmp) || - is_corrodeable(otmp) || - is_flammable(otmp)); + return (boolean)(is_rustprone(otmp) || + is_corrodeable(otmp) || + is_flammable(otmp)); } char * @@ -973,81 +976,81 @@ struct obj *otmp; const char *adjective; unsigned cxn_flags; /* bitmask of CXN_xxx values */ { - char *nambuf = nextobuf(); - int omndx = otmp->corpsenm; - boolean ignore_quan = (cxn_flags & CXN_SINGULAR) != 0, - /* suppress "the" from "the unique monster corpse" */ - no_prefix = (cxn_flags & CXN_NO_PFX) != 0, - /* include "the" for "the woodchuck corpse */ - the_prefix = (cxn_flags & CXN_PFX_THE) != 0, - /* include "an" for "an ogre corpse */ - any_prefix = (cxn_flags & CXN_ARTICLE) != 0, - /* leave off suffix (do_name() appends "corpse" itself) */ - omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, - possessive = FALSE; - const char *mname; - - if (omndx == NON_PM) { /* paranoia */ - mname = "thing"; - /* [Possible enhancement: check whether corpse has monster traits - attached in order to use priestname() for priests and minions.] */ - } else if (omndx == PM_ALIGNED_PRIEST) { - /* avoid "aligned priest"; it just exposes internal details */ - mname = "priest"; - } else { - mname = mons[omndx].mname; - if (the_unique_pm(&mons[omndx]) || type_is_pname(&mons[omndx])) { - mname = s_suffix(mname); - possessive = TRUE; - /* don't precede personal name like "Medusa" with an article */ - if (type_is_pname(&mons[omndx])) - no_prefix = TRUE; - /* always precede non-personal unique monster name like - "Oracle" with "the" unless explicitly overridden */ - else if (the_unique_pm(&mons[omndx]) && !no_prefix) - the_prefix = TRUE; - } - } - if (no_prefix) the_prefix = any_prefix = FALSE; - else if (the_prefix) any_prefix = FALSE; /* mutually exclusive */ - - *nambuf = '\0'; - /* can't use the() the way we use an() below because any capitalized - Name causes it to assume a personal name and return Name as-is; - that's usually the behavior wanted, but here we need to force "the" - to precede capitalized unique monsters (pnames are handled above) */ - if (the_prefix) Strcat(nambuf, "the "); - - if (!adjective || !*adjective) { - /* normal case: newt corpse */ - Strcat(nambuf, mname); - } else { - /* adjective positioning depends upon format of monster name */ - if (possessive) /* Medusa's cursed partly eaten corpse */ - Sprintf(eos(nambuf), "%s %s", mname, adjective); - else /* cursed partly eaten troll corpse */ - Sprintf(eos(nambuf), "%s %s", adjective, mname); - /* in case adjective has a trailing space, squeeze it out */ - mungspaces(nambuf); - /* doname() might include a count in the adjective argument; - if so, don't prepend an article */ - if (digit(*adjective)) any_prefix = FALSE; - } - - if (!omit_corpse) { - Strcat(nambuf, " corpse"); - /* makeplural(nambuf) => append "s" to "corpse" */ - if (otmp->quan > 1L && !ignore_quan) { - Strcat(nambuf, "s"); - any_prefix = FALSE; /* avoid "a newt corpses" */ - } - } - - /* it's safe to overwrite our nambuf after an() has copied - its old value into another buffer */ - if (any_prefix) Strcpy(nambuf, an(nambuf)); - - return nambuf; + char *nambuf = nextobuf(); + int omndx = otmp->corpsenm; + boolean ignore_quan = (cxn_flags & CXN_SINGULAR) != 0, + /* suppress "the" from "the unique monster corpse" */ + no_prefix = (cxn_flags & CXN_NO_PFX) != 0, + /* include "the" for "the woodchuck corpse */ + the_prefix = (cxn_flags & CXN_PFX_THE) != 0, + /* include "an" for "an ogre corpse */ + any_prefix = (cxn_flags & CXN_ARTICLE) != 0, + /* leave off suffix (do_name() appends "corpse" itself) */ + omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, + possessive = FALSE; + const char *mname; + + if (omndx == NON_PM) { /* paranoia */ + mname = "thing"; + /* [Possible enhancement: check whether corpse has monster traits + attached in order to use priestname() for priests and minions.] */ + } else if (omndx == PM_ALIGNED_PRIEST) { + /* avoid "aligned priest"; it just exposes internal details */ + mname = "priest"; + } else { + mname = mons[omndx].mname; + if (the_unique_pm(&mons[omndx]) || type_is_pname(&mons[omndx])) { + mname = s_suffix(mname); + possessive = TRUE; + /* don't precede personal name like "Medusa" with an article */ + if (type_is_pname(&mons[omndx])) + no_prefix = TRUE; + /* always precede non-personal unique monster name like + "Oracle" with "the" unless explicitly overridden */ + else if (the_unique_pm(&mons[omndx]) && !no_prefix) + the_prefix = TRUE; + } + } + if (no_prefix) the_prefix = any_prefix = FALSE; + else if (the_prefix) any_prefix = FALSE; /* mutually exclusive */ + + *nambuf = '\0'; + /* can't use the() the way we use an() below because any capitalized + Name causes it to assume a personal name and return Name as-is; + that's usually the behavior wanted, but here we need to force "the" + to precede capitalized unique monsters (pnames are handled above) */ + if (the_prefix) Strcat(nambuf, "the "); + + if (!adjective || !*adjective) { + /* normal case: newt corpse */ + Strcat(nambuf, mname); + } else { + /* adjective positioning depends upon format of monster name */ + if (possessive) /* Medusa's cursed partly eaten corpse */ + Sprintf(eos(nambuf), "%s %s", mname, adjective); + else /* cursed partly eaten troll corpse */ + Sprintf(eos(nambuf), "%s %s", adjective, mname); + /* in case adjective has a trailing space, squeeze it out */ + mungspaces(nambuf); + /* doname() might include a count in the adjective argument; + if so, don't prepend an article */ + if (digit(*adjective)) any_prefix = FALSE; + } + + if (!omit_corpse) { + Strcat(nambuf, " corpse"); + /* makeplural(nambuf) => append "s" to "corpse" */ + if (otmp->quan > 1L && !ignore_quan) { + Strcat(nambuf, "s"); + any_prefix = FALSE; /* avoid "a newt corpses" */ + } + } + + /* it's safe to overwrite our nambuf after an() has copied + its old value into another buffer */ + if (any_prefix) Strcpy(nambuf, an(nambuf)); + + return nambuf; } /* xname doesn't include monster type for "corpse"; cxname does */ @@ -1055,9 +1058,9 @@ char * cxname(obj) struct obj *obj; { - if (obj->otyp == CORPSE) - return corpse_xname(obj, (const char *)0, CXN_NORMAL); - return xname(obj); + if (obj->otyp == CORPSE) + return corpse_xname(obj, (const char *)0, CXN_NORMAL); + return xname(obj); } /* treat an object as fully ID'd when it might be used as reason for death */ @@ -1099,20 +1102,20 @@ struct obj *obj; /* format the object */ if (obj->otyp == CORPSE) { - buf = nextobuf(); - Strcpy(buf, corpse_xname(obj, (const char *)0, CXN_NORMAL)); + buf = nextobuf(); + Strcpy(buf, corpse_xname(obj, (const char *)0, CXN_NORMAL)); } else if (obj->otyp == SLIME_MOLD) { - /* concession to "most unique deaths competition" in the annual - devnull tournament, suppress player supplied fruit names because - those can be used to fake other objects and dungeon features */ - buf = nextobuf(); - Sprintf(buf, "deadly slime mold%s", plur(obj->quan)); + /* concession to "most unique deaths competition" in the annual + devnull tournament, suppress player supplied fruit names because + those can be used to fake other objects and dungeon features */ + buf = nextobuf(); + Sprintf(buf, "deadly slime mold%s", plur(obj->quan)); } else { - buf = xname(obj); + buf = xname(obj); } /* apply an article if appropriate; caller should always use KILLED_BY */ if (obj->quan == 1L && !strstri(buf, "'s ") && !strstri(buf, "s' ")) - buf = (obj_is_pname(obj) || the_unique_obj(obj)) ? the(buf) : an(buf); + buf = (obj_is_pname(obj) || the_unique_obj(obj)) ? the(buf) : an(buf); objects[obj->otyp].oc_name_known = save_ocknown; objects[obj->otyp].oc_uname = save_ocuname; @@ -1132,7 +1135,7 @@ unsigned lenlimit; { struct obj save_obj; char unamebuf[12], onamebuf[12], - *save_oname, *save_uname, *outbuf; + *save_oname, *save_uname, *outbuf; outbuf = (*func)(obj); if ((unsigned)strlen(outbuf) <= lenlimit) return outbuf; @@ -1140,40 +1143,40 @@ unsigned lenlimit; /* shorten called string to fairly small amount */ save_uname = objects[obj->otyp].oc_uname; if (save_uname && strlen(save_uname) >= sizeof unamebuf) { - (void) strncpy(unamebuf, save_uname, sizeof unamebuf - 4); - Strcpy(unamebuf + sizeof unamebuf - 4, "..."); - objects[obj->otyp].oc_uname = unamebuf; - releaseobuf(outbuf); - outbuf = (*func)(obj); - objects[obj->otyp].oc_uname = save_uname; /* restore called string */ - if ((unsigned)strlen(outbuf) <= lenlimit) return outbuf; + (void) strncpy(unamebuf, save_uname, sizeof unamebuf - 4); + Strcpy(unamebuf + sizeof unamebuf - 4, "..."); + objects[obj->otyp].oc_uname = unamebuf; + releaseobuf(outbuf); + outbuf = (*func)(obj); + objects[obj->otyp].oc_uname = save_uname; /* restore called string */ + if ((unsigned)strlen(outbuf) <= lenlimit) return outbuf; } /* shorten named string to fairly small amount */ save_oname = has_oname(obj) ? ONAME(obj) : 0; if (save_oname && strlen(save_oname) >= sizeof onamebuf) { - (void) strncpy(onamebuf, save_oname, sizeof onamebuf - 4); - Strcpy(onamebuf + sizeof onamebuf - 4, "..."); - ONAME(obj) = onamebuf; - releaseobuf(outbuf); - outbuf = (*func)(obj); - ONAME(obj) = save_oname; /* restore named string */ - if ((unsigned)strlen(outbuf) <= lenlimit) return outbuf; + (void) strncpy(onamebuf, save_oname, sizeof onamebuf - 4); + Strcpy(onamebuf + sizeof onamebuf - 4, "..."); + ONAME(obj) = onamebuf; + releaseobuf(outbuf); + outbuf = (*func)(obj); + ONAME(obj) = save_oname; /* restore named string */ + if ((unsigned)strlen(outbuf) <= lenlimit) return outbuf; } /* shorten both called and named strings; unamebuf and onamebuf have both already been populated */ if (save_uname && strlen(save_uname) >= sizeof unamebuf && - save_oname && strlen(save_oname) >= sizeof onamebuf) { - objects[obj->otyp].oc_uname = unamebuf; - ONAME(obj) = onamebuf; - releaseobuf(outbuf); - outbuf = (*func)(obj); - if ((unsigned)strlen(outbuf) <= lenlimit) { - objects[obj->otyp].oc_uname = save_uname; - ONAME(obj) = save_oname; - return outbuf; - } + save_oname && strlen(save_oname) >= sizeof onamebuf) { + objects[obj->otyp].oc_uname = unamebuf; + ONAME(obj) = onamebuf; + releaseobuf(outbuf); + outbuf = (*func)(obj); + if ((unsigned)strlen(outbuf) <= lenlimit) { + objects[obj->otyp].oc_uname = save_uname; + ONAME(obj) = save_oname; + return outbuf; + } } /* still long; strip several name-lengthening attributes; @@ -1184,10 +1187,10 @@ unsigned lenlimit; releaseobuf(outbuf); outbuf = (*func)(obj); if (altfunc && (unsigned)strlen(outbuf) > lenlimit) { - /* still long; use the alternate function (usually one of - the jackets around minimal_xname()) */ - releaseobuf(outbuf); - outbuf = (*altfunc)(obj); + /* still long; use the alternate function (usually one of + the jackets around minimal_xname()) */ + releaseobuf(outbuf); + outbuf = (*altfunc)(obj); } /* restore the object */ *obj = save_obj; @@ -1206,53 +1209,53 @@ singular(otmp, func) register struct obj *otmp; char *FDECL((*func), (OBJ_P)); { - long savequan; - char *nam; + long savequan; + char *nam; - /* using xname for corpses does not give the monster type */ - if (otmp->otyp == CORPSE && func == xname) func = cxname; + /* using xname for corpses does not give the monster type */ + if (otmp->otyp == CORPSE && func == xname) func = cxname; - savequan = otmp->quan; - otmp->quan = 1L; - nam = (*func)(otmp); - otmp->quan = savequan; - return nam; + savequan = otmp->quan; + otmp->quan = 1L; + nam = (*func)(otmp); + otmp->quan = savequan; + return nam; } char * an(str) register const char *str; { - char *buf = nextobuf(); - - buf[0] = '\0'; - - if (strncmpi(str, "the ", 4) && - strcmp(str, "molten lava") && - strcmp(str, "iron bars") && - strcmp(str, "ice")) { - if (index(vowels, *str) && - strncmp(str, "one-", 4) && - strncmp(str, "useful", 6) && - strncmp(str, "unicorn", 7) && - strncmp(str, "uranium", 7) && - strncmp(str, "eucalyptus", 10)) - Strcpy(buf, "an "); - else - Strcpy(buf, "a "); - } - - Strcat(buf, str); - return buf; + char *buf = nextobuf(); + + buf[0] = '\0'; + + if (strncmpi(str, "the ", 4) && + strcmp(str, "molten lava") && + strcmp(str, "iron bars") && + strcmp(str, "ice")) { + if (index(vowels, *str) && + strncmp(str, "one-", 4) && + strncmp(str, "useful", 6) && + strncmp(str, "unicorn", 7) && + strncmp(str, "uranium", 7) && + strncmp(str, "eucalyptus", 10)) + Strcpy(buf, "an "); + else + Strcpy(buf, "a "); + } + + Strcat(buf, str); + return buf; } char * An(str) const char *str; { - register char *tmp = an(str); - *tmp = highc(*tmp); - return tmp; + register char *tmp = an(str); + *tmp = highc(*tmp); + return tmp; } /* @@ -1263,47 +1266,47 @@ char * the(str) const char *str; { - char *buf = nextobuf(); - boolean insert_the = FALSE; - - if (!strncmpi(str, "the ", 4)) { - buf[0] = lowc(*str); - Strcpy(&buf[1], str+1); - return buf; - } else if (*str < 'A' || *str > 'Z') { - /* not a proper name, needs an article */ - insert_the = TRUE; - } else { - /* Probably a proper name, might not need an article */ - register char *tmp, *named, *called; - int l; - - /* some objects have capitalized adjectives in their names */ - if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) && - (tmp[1] < 'A' || tmp[1] > 'Z')) - insert_the = TRUE; - else if (tmp && index(str, ' ') < tmp) { /* has spaces */ - /* it needs an article if the name contains "of" */ - tmp = strstri(str, " of "); - named = strstri(str, " named "); - called = strstri(str, " called "); - if (called && (!named || called < named)) named = called; - - if (tmp && (!named || tmp < named)) /* found an "of" */ - insert_the = TRUE; - /* stupid special case: lacks "of" but needs "the" */ - else if (!named && (l = strlen(str)) >= 31 && - !strcmp(&str[l - 31], "Platinum Yendorian Express Card")) - insert_the = TRUE; - } - } - if (insert_the) - Strcpy(buf, "the "); - else - buf[0] = '\0'; - Strcat(buf, str); - - return buf; + char *buf = nextobuf(); + boolean insert_the = FALSE; + + if (!strncmpi(str, "the ", 4)) { + buf[0] = lowc(*str); + Strcpy(&buf[1], str+1); + return buf; + } else if (*str < 'A' || *str > 'Z') { + /* not a proper name, needs an article */ + insert_the = TRUE; + } else { + /* Probably a proper name, might not need an article */ + register char *tmp, *named, *called; + int l; + + /* some objects have capitalized adjectives in their names */ + if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) && + (tmp[1] < 'A' || tmp[1] > 'Z')) + insert_the = TRUE; + else if (tmp && index(str, ' ') < tmp) { /* has spaces */ + /* it needs an article if the name contains "of" */ + tmp = strstri(str, " of "); + named = strstri(str, " named "); + called = strstri(str, " called "); + if (called && (!named || called < named)) named = called; + + if (tmp && (!named || tmp < named)) /* found an "of" */ + insert_the = TRUE; + /* stupid special case: lacks "of" but needs "the" */ + else if (!named && (l = strlen(str)) >= 31 && + !strcmp(&str[l - 31], "Platinum Yendorian Express Card")) + insert_the = TRUE; + } + } + if (insert_the) + Strcpy(buf, "the "); + else + buf[0] = '\0'; + Strcat(buf, str); + + return buf; } char * @@ -1321,19 +1324,19 @@ aobjnam(otmp,verb) register struct obj *otmp; register const char *verb; { - register char *bp = cxname(otmp); - char prefix[PREFIX]; - - if(otmp->quan != 1L) { - Sprintf(prefix, "%ld ", otmp->quan); - bp = strprepend(bp, prefix); - } - - if(verb) { - Strcat(bp, " "); - Strcat(bp, otense(otmp, verb)); - } - return(bp); + register char *bp = cxname(otmp); + char prefix[PREFIX]; + + if(otmp->quan != 1L) { + Sprintf(prefix, "%ld ", otmp->quan); + bp = strprepend(bp, prefix); + } + + if(verb) { + Strcat(bp, " "); + Strcat(bp, otense(otmp, verb)); + } + return(bp); } /* combine yname and aobjnam eg "your count cxname(otmp)" */ @@ -1342,19 +1345,19 @@ yobjnam(obj,verb) struct obj *obj; const char *verb; { - char *s = aobjnam(obj, verb); + char *s = aobjnam(obj, verb); - /* leave off "your" for most of your artifacts, but prepend - * "your" for unique objects and "foo of bar" quest artifacts */ - if (!carried(obj) || !obj_is_pname(obj) || - obj->oartifact >= ART_ORB_OF_DETECTION) { - char *outbuf = shk_your(nextobuf(), obj); - int space_left = BUFSZ - 1 - strlen(outbuf); + /* leave off "your" for most of your artifacts, but prepend + * "your" for unique objects and "foo of bar" quest artifacts */ + if (!carried(obj) || !obj_is_pname(obj) || + obj->oartifact >= ART_ORB_OF_DETECTION) { + char *outbuf = shk_your(nextobuf(), obj); + int space_left = BUFSZ - 1 - strlen(outbuf); - s = strncat(outbuf, s, space_left); - } + s = strncat(outbuf, s, space_left); + } - return s; + return s; } /* combine Yname2 and aobjnam eg "Your count cxname(otmp)" */ @@ -1363,10 +1366,10 @@ Yobjnam2(obj,verb) struct obj *obj; const char *verb; { - register char *s = yobjnam(obj,verb); + register char *s = yobjnam(obj,verb); - *s = highc(*s); - return(s); + *s = highc(*s); + return(s); } /* like aobjnam, but prepend "The", not count, and use xname */ @@ -1375,13 +1378,13 @@ Tobjnam(otmp, verb) register struct obj *otmp; register const char *verb; { - char *bp = The(xname(otmp)); + char *bp = The(xname(otmp)); - if(verb) { - Strcat(bp, " "); - Strcat(bp, otense(otmp, verb)); - } - return(bp); + if(verb) { + Strcat(bp, " "); + Strcat(bp, otense(otmp, verb)); + } + return(bp); } /* capitalized variant of doname() */ @@ -1389,10 +1392,10 @@ char * Doname2(obj) register struct obj *obj; { - register char *s = doname(obj); + register char *s = doname(obj); - *s = highc(*s); - return(s); + *s = highc(*s); + return(s); } /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */ @@ -1400,19 +1403,19 @@ char * yname(obj) struct obj *obj; { - char *s = cxname(obj); + char *s = cxname(obj); - /* leave off "your" for most of your artifacts, but prepend - * "your" for unique objects and "foo of bar" quest artifacts */ - if (!carried(obj) || !obj_is_pname(obj) || - obj->oartifact >= ART_ORB_OF_DETECTION) { - char *outbuf = shk_your(nextobuf(), obj); - int space_left = BUFSZ - 1 - strlen(outbuf); + /* leave off "your" for most of your artifacts, but prepend + * "your" for unique objects and "foo of bar" quest artifacts */ + if (!carried(obj) || !obj_is_pname(obj) || + obj->oartifact >= ART_ORB_OF_DETECTION) { + char *outbuf = shk_your(nextobuf(), obj); + int space_left = BUFSZ - 1 - strlen(outbuf); - s = strncat(outbuf, s, space_left); - } + s = strncat(outbuf, s, space_left); + } - return s; + return s; } /* capitalized variant of yname() */ @@ -1420,10 +1423,10 @@ char * Yname2(obj) struct obj *obj; { - char *s = yname(obj); + char *s = yname(obj); - *s = highc(*s); - return s; + *s = highc(*s); + return s; } /* returns "your minimal_xname(obj)" @@ -1434,11 +1437,11 @@ char * ysimple_name(obj) struct obj *obj; { - char *outbuf = nextobuf(); - char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */ - int space_left = BUFSZ - 1 - strlen(s); + char *outbuf = nextobuf(); + char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */ + int space_left = BUFSZ - 1 - strlen(s); - return strncat(s, minimal_xname(obj), space_left); + return strncat(s, minimal_xname(obj), space_left); } /* capitalized variant of ysimple_name() */ @@ -1446,10 +1449,10 @@ char * Ysimple_name2(obj) struct obj *obj; { - char *s = ysimple_name(obj); + char *s = ysimple_name(obj); - *s = highc(*s); - return s; + *s = highc(*s); + return s; } /* "scroll" or "scrolls" */ @@ -1457,10 +1460,10 @@ char * simpleonames(obj) struct obj *obj; { - char *simpleoname = minimal_xname(obj); + char *simpleoname = minimal_xname(obj); - if (obj->quan != 1L) simpleoname = makeplural(simpleoname); - return simpleoname; + if (obj->quan != 1L) simpleoname = makeplural(simpleoname); + return simpleoname; } /* "a scroll" or "scrolls"; "a silver bell" or "the Bell of Opening" */ @@ -1468,20 +1471,20 @@ char * ansimpleoname(obj) struct obj *obj; { - char *simpleoname = simpleonames(obj); - int otyp = obj->otyp; - - /* prefix with "the" if a unique item, or a fake one imitating same, - has been formatted with its actual name (we let typename() handle - any `known' and `dknown' checking necessary) */ - if (otyp == FAKE_AMULET_OF_YENDOR) otyp = AMULET_OF_YENDOR; - if (objects[otyp].oc_unique && - !strcmp(simpleoname, OBJ_NAME(objects[otyp]))) - return the(simpleoname); - - /* simpleoname is singular if quan==1, plural otherwise */ - if (obj->quan == 1L) simpleoname = an(simpleoname); - return simpleoname; + char *simpleoname = simpleonames(obj); + int otyp = obj->otyp; + + /* prefix with "the" if a unique item, or a fake one imitating same, + has been formatted with its actual name (we let typename() handle + any `known' and `dknown' checking necessary) */ + if (otyp == FAKE_AMULET_OF_YENDOR) otyp = AMULET_OF_YENDOR; + if (objects[otyp].oc_unique && + !strcmp(simpleoname, OBJ_NAME(objects[otyp]))) + return the(simpleoname); + + /* simpleoname is singular if quan==1, plural otherwise */ + if (obj->quan == 1L) simpleoname = an(simpleoname); + return simpleoname; } /* "the scroll" or "the scrolls" */ @@ -1489,9 +1492,9 @@ char * thesimpleoname(obj) struct obj *obj; { - char *simpleoname = simpleonames(obj); + char *simpleoname = simpleonames(obj); - return the(simpleoname); + return the(simpleoname); } /* artifact's name without any object type or known/dknown/&c feedback */ @@ -1499,29 +1502,29 @@ char * bare_artifactname(obj) struct obj *obj; { - char *outbuf; - - if (obj->oartifact) { - outbuf = nextobuf(); - Strcpy(outbuf, artiname(obj->oartifact)); - if (!strncmp(outbuf, "The ", 4)) outbuf[0] = lowc(outbuf[0]); - } else { - outbuf = xname(obj); - } - return outbuf; + char *outbuf; + + if (obj->oartifact) { + outbuf = nextobuf(); + Strcpy(outbuf, artiname(obj->oartifact)); + if (!strncmp(outbuf, "The ", 4)) outbuf[0] = lowc(outbuf[0]); + } else { + outbuf = xname(obj); + } + return outbuf; } static const char *wrp[] = { - "wand", "ring", "potion", "scroll", "gem", "amulet", - "spellbook", "spell book", - /* for non-specific wishes */ - "weapon", "armor", "tool", "food", "comestible", + "wand", "ring", "potion", "scroll", "gem", "amulet", + "spellbook", "spell book", + /* for non-specific wishes */ + "weapon", "armor", "tool", "food", "comestible", }; static const char wrpsym[] = { - WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS, - AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS, - WEAPON_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS, - FOOD_CLASS + WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS, + AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS, + WEAPON_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS, + FOOD_CLASS }; /* return form of the verb (input plural) if xname(otmp) were the subject */ @@ -1538,7 +1541,7 @@ register const char *verb; * recomputing xname(otmp) at this time. */ if (!is_plural(otmp)) - return vtense((char *)0, verb); + return vtense((char *)0, verb); buf = nextobuf(); Strcpy(buf, verb); @@ -1548,22 +1551,22 @@ register const char *verb; /* various singular words that vtense would otherwise categorize as plural; also used by makesingular() to catch some special cases */ static const char * const special_subjs[] = { - "erinys", - "manes", /* this one is ambiguous */ - "Cyclops", - "Hippocrates", - "Pelias", - "aklys", - "amnesia", - "detect monsters", - "paralysis", - "shape changers", - "nemesis", - 0 - /* note: "detect monsters" and "shape changers" are normally - caught via "(s) of ", but they can be - wished for using the shorter form, so we include them here - to accomodate usage by makesingular during wishing */ + "erinys", + "manes", /* this one is ambiguous */ + "Cyclops", + "Hippocrates", + "Pelias", + "aklys", + "amnesia", + "detect monsters", + "paralysis", + "shape changers", + "nemesis", + 0 + /* note: "detect monsters" and "shape changers" are normally + caught via "(s) of ", but they can be + wished for using the shorter form, so we include them here + to accomodate usage by makesingular during wishing */ }; /* return form of the verb (input plural) for present tense 3rd person subj */ @@ -1588,51 +1591,51 @@ register const char *verb; * present tense form so we don't duplicate this code elsewhere. */ if (subj) { - if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3)) - goto sing; - spot = (const char *)0; - for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) { - if (!strncmpi(sp, " of ", 4) || - !strncmpi(sp, " from ", 6) || - !strncmpi(sp, " called ", 8) || - !strncmpi(sp, " named ", 7) || - !strncmpi(sp, " labeled ", 9)) { - if (sp != subj) spot = sp - 1; - break; - } - } - len = (int) strlen(subj); - if (!spot) spot = subj + len - 1; - - /* - * plural: anything that ends in 's', but not '*us' or '*ss'. - * Guess at a few other special cases that makeplural creates. - */ - if ((lowc(*spot) == 's' && spot != subj && - !index("us", lowc(*(spot-1)))) || - !BSTRNCMPI(subj, spot-3, "eeth", 4) || - !BSTRNCMPI(subj, spot-3, "feet", 4) || - !BSTRNCMPI(subj, spot-1, "ia", 2) || - !BSTRNCMPI(subj, spot-1, "ae", 2)) { - /* check for special cases to avoid false matches */ - len = (int)(spot - subj) + 1; - for (spec = special_subjs; *spec; spec++) { - ltmp = strlen(*spec); - if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing; - /* also check for - to catch things like "the invisible erinys" */ - if (len > ltmp && *(spot - ltmp) == ' ' && - !strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing; - } - - return strcpy(buf, verb); - } - /* - * 3rd person plural doesn't end in telltale 's'; - * 2nd person singular behaves as if plural. - */ - if (!strcmpi(subj, "they") || !strcmpi(subj, "you")) - return strcpy(buf, verb); + if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3)) + goto sing; + spot = (const char *)0; + for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) { + if (!strncmpi(sp, " of ", 4) || + !strncmpi(sp, " from ", 6) || + !strncmpi(sp, " called ", 8) || + !strncmpi(sp, " named ", 7) || + !strncmpi(sp, " labeled ", 9)) { + if (sp != subj) spot = sp - 1; + break; + } + } + len = (int) strlen(subj); + if (!spot) spot = subj + len - 1; + + /* + * plural: anything that ends in 's', but not '*us' or '*ss'. + * Guess at a few other special cases that makeplural creates. + */ + if ((lowc(*spot) == 's' && spot != subj && + !index("us", lowc(*(spot-1)))) || + !BSTRNCMPI(subj, spot-3, "eeth", 4) || + !BSTRNCMPI(subj, spot-3, "feet", 4) || + !BSTRNCMPI(subj, spot-1, "ia", 2) || + !BSTRNCMPI(subj, spot-1, "ae", 2)) { + /* check for special cases to avoid false matches */ + len = (int)(spot - subj) + 1; + for (spec = special_subjs; *spec; spec++) { + ltmp = strlen(*spec); + if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing; + /* also check for + to catch things like "the invisible erinys" */ + if (len > ltmp && *(spot - ltmp) == ' ' && + !strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing; + } + + return strcpy(buf, verb); + } + /* + * 3rd person plural doesn't end in telltale 's'; + * 2nd person singular behaves as if plural. + */ + if (!strcmpi(subj, "they") || !strcmpi(subj, "you")) + return strcpy(buf, verb); } sing: @@ -1641,69 +1644,69 @@ register const char *verb; bspot = buf + len - 1; if (!strcmpi(buf, "are")) { - Strcasecpy(buf, "is"); + Strcasecpy(buf, "is"); } else if (!strcmpi(buf, "have")) { - Strcasecpy(bspot-1, "s"); + Strcasecpy(bspot-1, "s"); } else if (index("zxs", lowc(*bspot)) || - (len >= 2 && lowc(*bspot) == 'h' && - index("cs", lowc(*(bspot-1)))) || - (len == 2 && lowc(*bspot) == 'o')) { - /* Ends in z, x, s, ch, sh; add an "es" */ - Strcasecpy(bspot+1, "es"); + (len >= 2 && lowc(*bspot) == 'h' && + index("cs", lowc(*(bspot-1)))) || + (len == 2 && lowc(*bspot) == 'o')) { + /* Ends in z, x, s, ch, sh; add an "es" */ + Strcasecpy(bspot+1, "es"); } else if (lowc(*bspot) == 'y' && !index(vowels, lowc(*(bspot-1)))) { - /* like "y" case in makeplural */ - Strcasecpy(bspot, "ies"); + /* like "y" case in makeplural */ + Strcasecpy(bspot, "ies"); } else { - Strcasecpy(bspot+1, "s"); + Strcasecpy(bspot+1, "s"); } return buf; } struct sing_plur { - const char *sing, *plur; + const char *sing, *plur; }; /* word pairs that don't fit into formula-based transformations; also some suffices which have very few--often one--matches or which aren't systematically reversible (knives, staves) */ static struct sing_plur one_off[] = { - { "child", "children" }, /* (for wise guys who give their food funny names) */ - { "cubus", "cubi" }, /* in-/suc-cubus */ - { "culus", "culi" }, /* homunculus */ - { "djinni", "djinn" }, - { "erinys", "erinyes" }, - { "foot", "feet" }, - { "fungus", "fungi" }, - { "knife", "knives" }, - { "labrum", "labra" }, /* candelabrum */ - { "louse", "lice" }, - { "mouse", "mice" }, - { "mumak", "mumakil" }, - { "nemesis", "nemeses" }, - { "rtex", "rtices" }, /* vortex */ - { "tooth", "teeth" }, - { "staff", "staves" }, - { 0, 0 } + { "child", "children" }, /* (for wise guys who give their food funny names) */ + { "cubus", "cubi" }, /* in-/suc-cubus */ + { "culus", "culi" }, /* homunculus */ + { "djinni", "djinn" }, + { "erinys", "erinyes" }, + { "foot", "feet" }, + { "fungus", "fungi" }, + { "knife", "knives" }, + { "labrum", "labra" }, /* candelabrum */ + { "louse", "lice" }, + { "mouse", "mice" }, + { "mumak", "mumakil" }, + { "nemesis", "nemeses" }, + { "rtex", "rtices" }, /* vortex */ + { "tooth", "teeth" }, + { "staff", "staves" }, + { 0, 0 } }; static const char *const as_is[] = { - /* makesingular() leaves these plural due to how they're used */ - "boots", "shoes", - "gloves", "lenses", "scales", - "gauntlets", - "iron bars", - /* both singular and plural are spelled the same */ - "deer", "fish", "tuna", "yaki", "-hai", - "krill", "manes", "ninja", "sheep", "ronin", "roshi", "shito", "tengu", - "ki-rin", "Nazgul", - "gunyoki", "piranha", "samurai", - "shuriken", - 0, - /* Note: "fish" and "piranha" are collective plurals, suitable - for "wiped out all ". For "3 ", they should be - "fishes" and "piranhas" instead. We settle for collective - variant instead of attempting to support both. */ + /* makesingular() leaves these plural due to how they're used */ + "boots", "shoes", + "gloves", "lenses", "scales", + "gauntlets", + "iron bars", + /* both singular and plural are spelled the same */ + "deer", "fish", "tuna", "yaki", "-hai", + "krill", "manes", "ninja", "sheep", "ronin", "roshi", "shito", "tengu", + "ki-rin", "Nazgul", + "gunyoki", "piranha", "samurai", + "shuriken", + 0, + /* Note: "fish" and "piranha" are collective plurals, suitable + for "wiped out all ". For "3 ", they should be + "fishes" and "piranhas" instead. We settle for collective + variant instead of attempting to support both. */ }; /* singularize/pluralize decisiions common to both makesingular & makeplural */ @@ -1713,38 +1716,38 @@ char *basestr, *endstring; /* base string, pointer to eos(string) */ boolean to_plural; /* true => makeplural, false => makesingular */ const char *const *alt_as_is; /* another set like as_is[] */ { - const struct sing_plur *sp; - const char *same, *other, *const *as; - int al; - - for (as = as_is; *as; ++as) { - al = (int)strlen(*as); - if (!BSTRCMPI(basestr, endstring - al, *as)) - return TRUE; - } - if (alt_as_is) { - for (as = alt_as_is; *as; ++as) { - al = (int)strlen(*as); - if (!BSTRCMPI(basestr, endstring - al, *as)) - return TRUE; - } - } - - for (sp = one_off; sp->sing; sp++) { - /* check whether endstring already matches */ - same = to_plural ? sp->plur : sp->sing; - al = (int)strlen(same); - if (!BSTRCMPI(basestr, endstring - al, same)) - return TRUE; /* use as-is */ - /* check whether it matches the inverse; if so, transform it */ - other = to_plural ? sp->sing : sp->plur; - al = (int)strlen(other); - if (!BSTRCMPI(basestr, endstring - al, other)) { - Strcasecpy(endstring - al, same); - return TRUE; /* one_off[] transformation */ - } - } - return FALSE; + const struct sing_plur *sp; + const char *same, *other, *const *as; + int al; + + for (as = as_is; *as; ++as) { + al = (int)strlen(*as); + if (!BSTRCMPI(basestr, endstring - al, *as)) + return TRUE; + } + if (alt_as_is) { + for (as = alt_as_is; *as; ++as) { + al = (int)strlen(*as); + if (!BSTRCMPI(basestr, endstring - al, *as)) + return TRUE; + } + } + + for (sp = one_off; sp->sing; sp++) { + /* check whether endstring already matches */ + same = to_plural ? sp->plur : sp->sing; + al = (int)strlen(same); + if (!BSTRCMPI(basestr, endstring - al, same)) + return TRUE; /* use as-is */ + /* check whether it matches the inverse; if so, transform it */ + other = to_plural ? sp->sing : sp->plur; + al = (int)strlen(other); + if (!BSTRCMPI(basestr, endstring - al, other)) { + Strcasecpy(endstring - al, same); + return TRUE; /* one_off[] transformation */ + } + } + return FALSE; } /* searches for common compounds, ex. lump of royal jelly */ @@ -1754,37 +1757,37 @@ char *str; { /* if new entries are added, be sure to keep compound_start[] in sync */ static const char *const compounds[] = { - " of ", - " labeled ", - " called ", - " named ", - " above", /* lurkers above */ - " versus ", - " from ", - " in ", - " on ", - " a la ", - " with", /* " with "? */ - " de ", - " d'", - " du ", - "-in-", - "-at-", - 0 + " of ", + " labeled ", + " called ", + " named ", + " above", /* lurkers above */ + " versus ", + " from ", + " in ", + " on ", + " a la ", + " with", /* " with "? */ + " de ", + " d'", + " du ", + "-in-", + "-at-", + 0 }, /* list of first characters for all compounds[] entries */ - compound_start[] = " -"; + compound_start[] = " -"; const char *const *cmpd; char *p; for (p = str; *p; ++p) { - /* substring starting at p can only match if *p is found - within compound_start[] */ - if (!index(compound_start, *p)) continue; + /* substring starting at p can only match if *p is found + within compound_start[] */ + if (!index(compound_start, *p)) continue; - /* check current substring against all words in the compound[] list */ - for (cmpd = compounds; *cmpd; ++cmpd) - if (!strncmpi(p, *cmpd, (int)strlen(*cmpd))) return p; + /* check current substring against all words in the compound[] list */ + for (cmpd = compounds; *cmpd; ++cmpd) + if (!strncmpi(p, *cmpd, (int)strlen(*cmpd))) return p; } /* wasn't recognized as a compound phrase */ return 0; @@ -1809,151 +1812,151 @@ char * makeplural(oldstr) const char *oldstr; { - register char *spot; - char lo_c, *str = nextobuf(); - const char *excess = (char *)0; - int len; - - if (oldstr) while (*oldstr == ' ') oldstr++; - if (!oldstr || !*oldstr) { - impossible("plural of null?"); - Strcpy(str, "s"); - return str; - } - Strcpy(str, oldstr); - - /* - * Skip changing "pair of" to "pairs of". According to Webster, usual - * English usage is use pairs for humans, e.g. 3 pairs of dancers, - * and pair for objects and non-humans, e.g. 3 pair of boots. We don't - * refer to pairs of humans in this game so just skip to the bottom. - */ - if (!strncmpi(str, "pair of ", 8)) - goto bottom; - - /* look for "foo of bar" so that we can focus on "foo" */ - if ((spot = singplur_compound(str)) != 0) { - excess = oldstr + (int)(spot - str); - *spot = '\0'; - } else - spot = eos(str); - - spot--; - while (spot > str && *spot == ' ') spot--; /* Strip blanks from end */ - *(spot+1) = 0; - /* Now spot is the last character of the string */ - - len = strlen(str); - - /* Single letters */ - if (len==1 || !letter(*spot)) { - Strcpy(spot+1, "'s"); - goto bottom; - } - - /* dispense with some words which don't need pluralization */ + register char *spot; + char lo_c, *str = nextobuf(); + const char *excess = (char *)0; + int len; + + if (oldstr) while (*oldstr == ' ') oldstr++; + if (!oldstr || !*oldstr) { + impossible("plural of null?"); + Strcpy(str, "s"); + return str; + } + Strcpy(str, oldstr); + + /* + * Skip changing "pair of" to "pairs of". According to Webster, usual + * English usage is use pairs for humans, e.g. 3 pairs of dancers, + * and pair for objects and non-humans, e.g. 3 pair of boots. We don't + * refer to pairs of humans in this game so just skip to the bottom. + */ + if (!strncmpi(str, "pair of ", 8)) + goto bottom; + + /* look for "foo of bar" so that we can focus on "foo" */ + if ((spot = singplur_compound(str)) != 0) { + excess = oldstr + (int)(spot - str); + *spot = '\0'; + } else + spot = eos(str); + + spot--; + while (spot > str && *spot == ' ') spot--; /* Strip blanks from end */ + *(spot+1) = 0; + /* Now spot is the last character of the string */ + + len = strlen(str); + + /* Single letters */ + if (len==1 || !letter(*spot)) { + Strcpy(spot+1, "'s"); + goto bottom; + } + + /* dispense with some words which don't need pluralization */ { - static const char *const already_plural[] = { - "ae", /* algae, larvae, &c */ - "men", /* also catches women, watchmen */ - "matzot", - 0, - }; - - /* spot+1: synch up with makesingular's usage */ - if (singplur_lookup(str, spot + 1, TRUE, already_plural)) - goto bottom; - - /* more of same, but not suitable for blanket loop checking */ - if ((len == 2 && !strcmpi(str, "ya")) || - (len >= 3 && !strcmpi(spot-2, " ya"))) - goto bottom; - } - - /* man/men ("Wiped out all cavemen.") */ - if (len >= 3 && !strcmpi(spot-2, "man") && - /* exclude shamans and humans */ - (len < 6 || strcmpi(spot-5, "shaman")) && - (len < 5 || strcmpi(spot-4, "human"))) { - Strcasecpy(spot-1, "en"); - goto bottom; - } - if (lowc(*spot) == 'f') { /* (staff handled via one_off[]) */ - lo_c = lowc(*(spot-1)); - if (len >= 3 && !strcmpi(spot-2, "erf")) { - /* avoid "nerf" -> "nerves", "serf" -> "serves" */ - ; /* fall through to default (append 's') */ - } else if (index("lr", lo_c) || index(vowels, lo_c)) { - /* [aeioulr]f to [aeioulr]ves */ - Strcasecpy(spot, "ves"); - goto bottom; - } - } - /* ium/ia (mycelia, baluchitheria) */ - if (len >= 3 && !strcmpi(spot-2, "ium")) { - Strcasecpy(spot-2, "ia"); - goto bottom; - } - /* algae, larvae, hyphae (another fungus part) */ - if ((len >= 4 && !strcmpi(spot-3, "alga")) || - (len >= 5 && (!strcmpi(spot-4, "hypha") || - !strcmpi(spot-4, "larva"))) || - (len >= 6 && !strcmpi(spot-5, "amoeba")) || - (len >= 8 && (!strcmpi(spot-7, "vertebra")))) { - /* a to ae */ - Strcasecpy(spot+1, "e"); - goto bottom; - } - /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */ - if (len > 3 && !strcmpi(spot-1, "us") && - !((len >= 5 && !strcmpi(spot-4, "lotus")) || - (len >= 6 && !strcmpi(spot-5, "wumpus")))) { - Strcasecpy(spot-1, "i"); - goto bottom; - } - /* sis/ses (nemesis) */ - if (len >= 3 && !strcmpi(spot-2, "sis")) { - Strcasecpy(spot-1, "es"); - goto bottom; - } - /* matzoh/matzot, possible food name */ - if (len >= 6 && (!strcmpi(spot-5, "matzoh") || - !strcmpi(spot-5, "matzah"))) { - Strcasecpy(spot-1, "ot"); /* oh/ah -> ot */ - goto bottom; - } - if (len >= 5 && (!strcmpi(spot-4, "matzo") || - !strcmpi(spot-4, "matza"))) { - Strcasecpy(spot, "ot"); /* o/a -> ot */ - goto bottom; - } - - /* note: -eau/-eaux (gateau, bordeau...) */ - /* note: ox/oxen, VAX/VAXen, goose/geese */ - - lo_c = lowc(*spot); - - /* Ends in z, x, s, ch, sh; add an "es" */ - if (index("zxs", lo_c) || - (len >= 2 && lo_c == 'h' && index("cs", lowc(*(spot-1)))) || - /* Kludge to get "tomatoes" and "potatoes" right */ - (len >= 4 && !strcmpi(spot-2, "ato")) || - (len >= 5 && !strcmpi(spot-4, "dingo"))) { - Strcasecpy(spot+1, "es"); /* append es */ - goto bottom; - } - /* Ends in y preceded by consonant (note: also "qu") change to "ies" */ - if (lo_c == 'y' && - !index(vowels, lowc(*(spot-1)))) { - Strcasecpy(spot, "ies"); /* y -> ies */ - goto bottom; - } - /* Default: append an 's' */ - Strcasecpy(spot+1, "s"); + static const char *const already_plural[] = { + "ae", /* algae, larvae, &c */ + "men", /* also catches women, watchmen */ + "matzot", + 0, + }; + + /* spot+1: synch up with makesingular's usage */ + if (singplur_lookup(str, spot + 1, TRUE, already_plural)) + goto bottom; + + /* more of same, but not suitable for blanket loop checking */ + if ((len == 2 && !strcmpi(str, "ya")) || + (len >= 3 && !strcmpi(spot-2, " ya"))) + goto bottom; + } + + /* man/men ("Wiped out all cavemen.") */ + if (len >= 3 && !strcmpi(spot-2, "man") && + /* exclude shamans and humans */ + (len < 6 || strcmpi(spot-5, "shaman")) && + (len < 5 || strcmpi(spot-4, "human"))) { + Strcasecpy(spot-1, "en"); + goto bottom; + } + if (lowc(*spot) == 'f') { /* (staff handled via one_off[]) */ + lo_c = lowc(*(spot-1)); + if (len >= 3 && !strcmpi(spot-2, "erf")) { + /* avoid "nerf" -> "nerves", "serf" -> "serves" */ + ; /* fall through to default (append 's') */ + } else if (index("lr", lo_c) || index(vowels, lo_c)) { + /* [aeioulr]f to [aeioulr]ves */ + Strcasecpy(spot, "ves"); + goto bottom; + } + } + /* ium/ia (mycelia, baluchitheria) */ + if (len >= 3 && !strcmpi(spot-2, "ium")) { + Strcasecpy(spot-2, "ia"); + goto bottom; + } + /* algae, larvae, hyphae (another fungus part) */ + if ((len >= 4 && !strcmpi(spot-3, "alga")) || + (len >= 5 && (!strcmpi(spot-4, "hypha") || + !strcmpi(spot-4, "larva"))) || + (len >= 6 && !strcmpi(spot-5, "amoeba")) || + (len >= 8 && (!strcmpi(spot-7, "vertebra")))) { + /* a to ae */ + Strcasecpy(spot+1, "e"); + goto bottom; + } + /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */ + if (len > 3 && !strcmpi(spot-1, "us") && + !((len >= 5 && !strcmpi(spot-4, "lotus")) || + (len >= 6 && !strcmpi(spot-5, "wumpus")))) { + Strcasecpy(spot-1, "i"); + goto bottom; + } + /* sis/ses (nemesis) */ + if (len >= 3 && !strcmpi(spot-2, "sis")) { + Strcasecpy(spot-1, "es"); + goto bottom; + } + /* matzoh/matzot, possible food name */ + if (len >= 6 && (!strcmpi(spot-5, "matzoh") || + !strcmpi(spot-5, "matzah"))) { + Strcasecpy(spot-1, "ot"); /* oh/ah -> ot */ + goto bottom; + } + if (len >= 5 && (!strcmpi(spot-4, "matzo") || + !strcmpi(spot-4, "matza"))) { + Strcasecpy(spot, "ot"); /* o/a -> ot */ + goto bottom; + } + + /* note: -eau/-eaux (gateau, bordeau...) */ + /* note: ox/oxen, VAX/VAXen, goose/geese */ + + lo_c = lowc(*spot); + + /* Ends in z, x, s, ch, sh; add an "es" */ + if (index("zxs", lo_c) || + (len >= 2 && lo_c == 'h' && index("cs", lowc(*(spot-1)))) || + /* Kludge to get "tomatoes" and "potatoes" right */ + (len >= 4 && !strcmpi(spot-2, "ato")) || + (len >= 5 && !strcmpi(spot-4, "dingo"))) { + Strcasecpy(spot+1, "es"); /* append es */ + goto bottom; + } + /* Ends in y preceded by consonant (note: also "qu") change to "ies" */ + if (lo_c == 'y' && + !index(vowels, lowc(*(spot-1)))) { + Strcasecpy(spot, "ies"); /* y -> ies */ + goto bottom; + } + /* Default: append an 's' */ + Strcasecpy(spot+1, "s"); bottom: - if (excess) Strcat(str, excess); - return str; + if (excess) Strcat(str, excess); + return str; } /* @@ -1972,105 +1975,105 @@ char * makesingular(oldstr) const char *oldstr; { - register char *p, *bp; - const char *excess = 0; - char *str = nextobuf(); - - if (oldstr) while (*oldstr == ' ') oldstr++; - if (!oldstr || !*oldstr) { - impossible("singular of null?"); - str[0] = '\0'; - return str; - } - - bp = strcpy(str, oldstr); - - /* check for "foo of bar" so that we can focus on "foo" */ - if ((p = singplur_compound(bp)) != 0) { - excess = oldstr + (int)(p - bp); - *p = '\0'; - } else - p = eos(bp); - - /* dispense with some words which don't need singularization */ - if (singplur_lookup(bp, p, FALSE, special_subjs)) - goto bottom; - - /* remove -s or -es (boxes) or -ies (rubies) */ - if (p >= bp+1 && lowc(p[-1]) == 's') { - if (p >= bp+2 && lowc(p[-2]) == 'e') { - if (p >= bp+3 && lowc(p[-3]) == 'i') { /* "ies" */ - if (!BSTRCMPI(bp, p-7, "cookies") || - !BSTRCMPI(bp, p-4, "pies") || - !BSTRCMPI(bp, p-5, "mbies") || /* zombie */ - !BSTRCMPI(bp, p-5, "yries")) /* valkyrie */ - goto mins; - Strcasecpy(p-3, "y"); /* ies -> y */ - goto bottom; - } - /* wolves, but f to ves isn't fully reversible */ - if (p-4 >= bp && (index("lr", lowc(*(p-4))) || - index(vowels, lowc(*(p-4)))) && - !BSTRCMPI(bp, p-3, "ves")) { - if (!BSTRCMPI(bp, p-6, "cloves") || - !BSTRCMPI(bp, p-6, "nerves")) goto mins; - Strcasecpy(p-3, "f"); /* ves -> f */ - goto bottom; - } - /* note: nurses, axes but boxes, wumpuses */ - if (!BSTRCMPI(bp, p-4, "eses") || - !BSTRCMPI(bp, p-4, "oxes") || /* boxes, foxes */ - !BSTRCMPI(bp, p-4, "nxes") || /* lynxes */ - !BSTRCMPI(bp, p-4, "ches") || - !BSTRCMPI(bp, p-4, "uses") || /* lotuses */ - !BSTRCMPI(bp, p-4, "sses") || /* priestesses */ - !BSTRCMPI(bp, p-5, "atoes") || /* tomatoes */ - !BSTRCMPI(bp, p-7, "dingoes") || - !BSTRCMPI(bp, p-7, "Aleaxes")) { - *(p-2) = '\0'; /* drop es */ - goto bottom; - } /* else fall through to mins */ - - /* ends in 's' but not 'es' */ - } else if (!BSTRCMPI(bp, p-2, "us")) { /* lotus, fungus... */ - if (BSTRCMPI(bp, p-6, "tengus") && /* but not these... */ - BSTRCMPI(bp, p-7, "hezrous")) - goto bottom; - } else if (!BSTRCMPI(bp, p-2, "ss") || - !BSTRCMPI(bp, p-5, " lens") || - (p-4 == bp && !strcmpi(p-4, "lens"))) { - goto bottom; - } - mins: - *(p-1) = '\0'; /* drop s */ - - } else { /* input doesn't end in 's' */ - - if (!BSTRCMPI(bp, p-3, "men")) { - Strcasecpy(p-2, "an"); - goto bottom; - } - /* matzot -> matzo, algae -> alga */ - if (!BSTRCMPI(bp, p-6, "matzot") || - !BSTRCMPI(bp, p-2, "ae")) { - *(p-1) = '\0'; /* drop t/e */ - goto bottom; - } - /* balactheria -> balactherium */ - if (p-4 >= bp && !strcmpi(p-2, "ia") && - index("lr", lowc(*(p-3))) && lowc(*(p-4)) == 'e') { - Strcasecpy(p-1, "um"); /* a -> um */ - } - - /* here we cannot find the plural suffix */ - } + register char *p, *bp; + const char *excess = 0; + char *str = nextobuf(); + + if (oldstr) while (*oldstr == ' ') oldstr++; + if (!oldstr || !*oldstr) { + impossible("singular of null?"); + str[0] = '\0'; + return str; + } + + bp = strcpy(str, oldstr); + + /* check for "foo of bar" so that we can focus on "foo" */ + if ((p = singplur_compound(bp)) != 0) { + excess = oldstr + (int)(p - bp); + *p = '\0'; + } else + p = eos(bp); + + /* dispense with some words which don't need singularization */ + if (singplur_lookup(bp, p, FALSE, special_subjs)) + goto bottom; + + /* remove -s or -es (boxes) or -ies (rubies) */ + if (p >= bp+1 && lowc(p[-1]) == 's') { + if (p >= bp+2 && lowc(p[-2]) == 'e') { + if (p >= bp+3 && lowc(p[-3]) == 'i') { /* "ies" */ + if (!BSTRCMPI(bp, p-7, "cookies") || + !BSTRCMPI(bp, p-4, "pies") || + !BSTRCMPI(bp, p-5, "mbies") || /* zombie */ + !BSTRCMPI(bp, p-5, "yries")) /* valkyrie */ + goto mins; + Strcasecpy(p-3, "y"); /* ies -> y */ + goto bottom; + } + /* wolves, but f to ves isn't fully reversible */ + if (p-4 >= bp && (index("lr", lowc(*(p-4))) || + index(vowels, lowc(*(p-4)))) && + !BSTRCMPI(bp, p-3, "ves")) { + if (!BSTRCMPI(bp, p-6, "cloves") || + !BSTRCMPI(bp, p-6, "nerves")) goto mins; + Strcasecpy(p-3, "f"); /* ves -> f */ + goto bottom; + } + /* note: nurses, axes but boxes, wumpuses */ + if (!BSTRCMPI(bp, p-4, "eses") || + !BSTRCMPI(bp, p-4, "oxes") || /* boxes, foxes */ + !BSTRCMPI(bp, p-4, "nxes") || /* lynxes */ + !BSTRCMPI(bp, p-4, "ches") || + !BSTRCMPI(bp, p-4, "uses") || /* lotuses */ + !BSTRCMPI(bp, p-4, "sses") || /* priestesses */ + !BSTRCMPI(bp, p-5, "atoes") || /* tomatoes */ + !BSTRCMPI(bp, p-7, "dingoes") || + !BSTRCMPI(bp, p-7, "Aleaxes")) { + *(p-2) = '\0'; /* drop es */ + goto bottom; + } /* else fall through to mins */ + + /* ends in 's' but not 'es' */ + } else if (!BSTRCMPI(bp, p-2, "us")) { /* lotus, fungus... */ + if (BSTRCMPI(bp, p-6, "tengus") && /* but not these... */ + BSTRCMPI(bp, p-7, "hezrous")) + goto bottom; + } else if (!BSTRCMPI(bp, p-2, "ss") || + !BSTRCMPI(bp, p-5, " lens") || + (p-4 == bp && !strcmpi(p-4, "lens"))) { + goto bottom; + } + mins: + *(p-1) = '\0'; /* drop s */ + + } else { /* input doesn't end in 's' */ + + if (!BSTRCMPI(bp, p-3, "men")) { + Strcasecpy(p-2, "an"); + goto bottom; + } + /* matzot -> matzo, algae -> alga */ + if (!BSTRCMPI(bp, p-6, "matzot") || + !BSTRCMPI(bp, p-2, "ae")) { + *(p-1) = '\0'; /* drop t/e */ + goto bottom; + } + /* balactheria -> balactherium */ + if (p-4 >= bp && !strcmpi(p-2, "ia") && + index("lr", lowc(*(p-3))) && lowc(*(p-4)) == 'e') { + Strcasecpy(p-1, "um"); /* a -> um */ + } + + /* here we cannot find the plural suffix */ + } bottom: - /* if we stripped off a suffix (" of bar" from "foo of bar"), - put it back now [strcat() isn't actually 100% safe here...] */ - if (excess) Strcat(bp, excess); + /* if we stripped off a suffix (" of bar" from "foo of bar"), + put it back now [strcat() isn't actually 100% safe here...] */ + if (excess) Strcat(bp, excess); - return bp; + return bp; } /* compare user string against object name string using fuzzy matching */ @@ -2080,117 +2083,117 @@ const char *u_str; /* from user, so might be variant spelling */ const char *o_str; /* from objects[], so is in canonical form */ boolean retry_inverted; /* optional extra "of" handling */ { - static NEARDATA const char - detect_SP[] = "detect ", SP_detection[] = " detection"; - char *p, buf[BUFSZ]; - - /* ignore spaces & hyphens and upper/lower case when comparing */ - if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE; - - if (retry_inverted) { - const char *u_of, *o_of; - - /* when just one of the strings is in the form "foo of bar", - convert it into "bar foo" and perform another comparison */ - u_of = strstri(u_str, " of "); - o_of = strstri(o_str, " of "); - if (u_of && !o_of) { - Strcpy(buf, u_of + 4); - p = eos(strcat(buf, " ")); - while (u_str < u_of) *p++ = *u_str++; - *p = '\0'; - return fuzzymatch(buf, o_str, " -", TRUE); - } else if (o_of && !u_of) { - Strcpy(buf, o_of + 4); - p = eos(strcat(buf, " ")); - while (o_str < o_of) *p++ = *o_str++; - *p = '\0'; - return fuzzymatch(u_str, buf, " -", TRUE); - } - } - - /* [note: if something like "elven speed boots" ever gets added, these - special cases should be changed to call wishymatch() recursively in - order to get the "of" inversion handling] */ - if (!strncmp(o_str, "dwarvish ", 9)) { - if (!strncmpi(u_str, "dwarven ", 8)) - return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE); - } else if (!strncmp(o_str, "elven ", 6)) { - if (!strncmpi(u_str, "elvish ", 7)) - return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE); - else if (!strncmpi(u_str, "elfin ", 6)) - return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE); - } else if (!strncmp(o_str, detect_SP, sizeof detect_SP - 1)) { - /* check for "detect " vs " detection" */ - if ((p = strstri(u_str, SP_detection)) != 0 && - !*(p + sizeof SP_detection - 1)) { - /* convert " detection" into "detect " */ - *p = '\0'; - Strcat(strcpy(buf, detect_SP), u_str); - /* "detect monster" -> "detect monsters" */ - if (!strcmpi(u_str, "monster")) Strcat(buf, "s"); - *p = ' '; - return fuzzymatch(buf, o_str, " -", TRUE); - } - } else if (strstri(o_str, SP_detection)) { - /* and the inverse, " detection" vs "detect " */ - if (!strncmpi(u_str, detect_SP, sizeof detect_SP - 1)) { - /* convert "detect s" into " detection" */ - p = makesingular(u_str + sizeof detect_SP - 1); - Strcat(strcpy(buf, p), SP_detection); - /* caller may be looping through objects[], so avoid - churning through all the obufs */ - releaseobuf(p); - return fuzzymatch(buf, o_str, " -", TRUE); - } - } else if (strstri(o_str, "ability")) { - /* when presented with "foo of bar", make singular() used to - singularize both foo & bar, but now only does so for foo */ - /* catch "{potion(s),ring} of {gain,restore,sustain} abilities" */ - if ((p = strstri(u_str, "abilities")) != 0 && - !*(p + sizeof "abilities" - 1)) { - (void)strncpy(buf, u_str, (unsigned)(p - u_str)); - Strcpy(buf + (p - u_str), "ability"); - return fuzzymatch(buf, o_str, " -", TRUE); - } - } else if (!strcmp(o_str, "aluminum")) { - /* this special case doesn't really fit anywhere else... */ - /* (note that " wand" will have been stripped off by now) */ - if (!strcmpi(u_str, "aluminium")) - return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE); - } - - return FALSE; + static NEARDATA const char + detect_SP[] = "detect ", SP_detection[] = " detection"; + char *p, buf[BUFSZ]; + + /* ignore spaces & hyphens and upper/lower case when comparing */ + if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE; + + if (retry_inverted) { + const char *u_of, *o_of; + + /* when just one of the strings is in the form "foo of bar", + convert it into "bar foo" and perform another comparison */ + u_of = strstri(u_str, " of "); + o_of = strstri(o_str, " of "); + if (u_of && !o_of) { + Strcpy(buf, u_of + 4); + p = eos(strcat(buf, " ")); + while (u_str < u_of) *p++ = *u_str++; + *p = '\0'; + return fuzzymatch(buf, o_str, " -", TRUE); + } else if (o_of && !u_of) { + Strcpy(buf, o_of + 4); + p = eos(strcat(buf, " ")); + while (o_str < o_of) *p++ = *o_str++; + *p = '\0'; + return fuzzymatch(u_str, buf, " -", TRUE); + } + } + + /* [note: if something like "elven speed boots" ever gets added, these + special cases should be changed to call wishymatch() recursively in + order to get the "of" inversion handling] */ + if (!strncmp(o_str, "dwarvish ", 9)) { + if (!strncmpi(u_str, "dwarven ", 8)) + return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE); + } else if (!strncmp(o_str, "elven ", 6)) { + if (!strncmpi(u_str, "elvish ", 7)) + return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE); + else if (!strncmpi(u_str, "elfin ", 6)) + return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE); + } else if (!strncmp(o_str, detect_SP, sizeof detect_SP - 1)) { + /* check for "detect " vs " detection" */ + if ((p = strstri(u_str, SP_detection)) != 0 && + !*(p + sizeof SP_detection - 1)) { + /* convert " detection" into "detect " */ + *p = '\0'; + Strcat(strcpy(buf, detect_SP), u_str); + /* "detect monster" -> "detect monsters" */ + if (!strcmpi(u_str, "monster")) Strcat(buf, "s"); + *p = ' '; + return fuzzymatch(buf, o_str, " -", TRUE); + } + } else if (strstri(o_str, SP_detection)) { + /* and the inverse, " detection" vs "detect " */ + if (!strncmpi(u_str, detect_SP, sizeof detect_SP - 1)) { + /* convert "detect s" into " detection" */ + p = makesingular(u_str + sizeof detect_SP - 1); + Strcat(strcpy(buf, p), SP_detection); + /* caller may be looping through objects[], so avoid + churning through all the obufs */ + releaseobuf(p); + return fuzzymatch(buf, o_str, " -", TRUE); + } + } else if (strstri(o_str, "ability")) { + /* when presented with "foo of bar", make singular() used to + singularize both foo & bar, but now only does so for foo */ + /* catch "{potion(s),ring} of {gain,restore,sustain} abilities" */ + if ((p = strstri(u_str, "abilities")) != 0 && + !*(p + sizeof "abilities" - 1)) { + (void)strncpy(buf, u_str, (unsigned)(p - u_str)); + Strcpy(buf + (p - u_str), "ability"); + return fuzzymatch(buf, o_str, " -", TRUE); + } + } else if (!strcmp(o_str, "aluminum")) { + /* this special case doesn't really fit anywhere else... */ + /* (note that " wand" will have been stripped off by now) */ + if (!strcmpi(u_str, "aluminium")) + return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE); + } + + return FALSE; } struct o_range { - const char *name, oclass; - int f_o_range, l_o_range; + const char *name, oclass; + int f_o_range, l_o_range; }; /* wishable subranges of objects */ STATIC_OVL NEARDATA const struct o_range o_ranges[] = { - { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS }, - { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP }, - { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE }, - { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY }, - { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION }, - { "hat", ARMOR_CLASS, FEDORA, DUNCE_CAP }, - { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY }, - { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, - { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, - { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS }, - { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES }, - { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT }, - { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT }, - { "dragon scales", - ARMOR_CLASS, GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES }, - { "dragon scale mail", - ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL }, - { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA }, - { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM }, - { "gray stone", GEM_CLASS, LUCKSTONE, FLINT }, - { "grey stone", GEM_CLASS, LUCKSTONE, FLINT }, + { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS }, + { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP }, + { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE }, + { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY }, + { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION }, + { "hat", ARMOR_CLASS, FEDORA, DUNCE_CAP }, + { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY }, + { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, + { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, + { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS }, + { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES }, + { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT }, + { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT }, + { "dragon scales", + ARMOR_CLASS, GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES }, + { "dragon scale mail", + ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL }, + { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA }, + { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM }, + { "gray stone", GEM_CLASS, LUCKSTONE, FLINT }, + { "grey stone", GEM_CLASS, LUCKSTONE, FLINT }, }; /* alternate spellings; if the difference is only the presence or @@ -2198,33 +2201,33 @@ STATIC_OVL NEARDATA const struct o_range o_ranges[] = { vs "pick-axe") then there is no need for inclusion in this list; likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */ struct alt_spellings { - const char *sp; - int ob; + const char *sp; + int ob; } spellings[] = { - { "pickax", PICK_AXE }, - { "whip", BULLWHIP }, - { "saber", SILVER_SABER }, - { "silver sabre", SILVER_SABER }, - { "smooth shield", SHIELD_OF_REFLECTION }, - { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL }, - { "grey dragon scales", GRAY_DRAGON_SCALES }, - { "iron ball", HEAVY_IRON_BALL }, - { "lantern", BRASS_LANTERN }, - { "mattock", DWARVISH_MATTOCK }, - { "amulet of poison resistance", AMULET_VERSUS_POISON }, - { "potion of sleep", POT_SLEEPING }, - { "stone", ROCK }, - { "camera", EXPENSIVE_CAMERA }, - { "tee shirt", T_SHIRT }, - { "can", TIN }, - { "can opener", TIN_OPENER }, - { "kelp", KELP_FROND }, - { "eucalyptus", EUCALYPTUS_LEAF }, - { "hook", GRAPPLING_HOOK }, - { "grappling iron", GRAPPLING_HOOK }, - { "grapnel", GRAPPLING_HOOK }, - { "grapple", GRAPPLING_HOOK }, - { (const char *)0, 0 }, + { "pickax", PICK_AXE }, + { "whip", BULLWHIP }, + { "saber", SILVER_SABER }, + { "silver sabre", SILVER_SABER }, + { "smooth shield", SHIELD_OF_REFLECTION }, + { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL }, + { "grey dragon scales", GRAY_DRAGON_SCALES }, + { "iron ball", HEAVY_IRON_BALL }, + { "lantern", BRASS_LANTERN }, + { "mattock", DWARVISH_MATTOCK }, + { "amulet of poison resistance", AMULET_VERSUS_POISON }, + { "potion of sleep", POT_SLEEPING }, + { "stone", ROCK }, + { "camera", EXPENSIVE_CAMERA }, + { "tee shirt", T_SHIRT }, + { "can", TIN }, + { "can opener", TIN_OPENER }, + { "kelp", KELP_FROND }, + { "eucalyptus", EUCALYPTUS_LEAF }, + { "hook", GRAPPLING_HOOK }, + { "grappling iron", GRAPPLING_HOOK }, + { "grapnel", GRAPPLING_HOOK }, + { "grapple", GRAPPLING_HOOK }, + { (const char *)0, 0 }, }; /* @@ -2239,1033 +2242,1033 @@ readobjnam(bp, no_wish) register char *bp; struct obj *no_wish; { - register char *p; - register int i; - register struct obj *otmp; - int cnt, spe, spesgn, typ, very, rechrg; - int blessed, uncursed, iscursed, ispoisoned, isgreased; - int eroded, eroded2, erodeproof; - int halfeaten, mntmp, contents; - int islit, unlabeled, ishistoric, isdiluted, trapped; - int tmp, tinv, tvariety; - struct fruit *f; - int ftype = context.current_fruit; - char fruitbuf[BUFSZ]; - /* Fruits may not mess up the ability to wish for real objects (since - * you can leave a fruit in a bones file and it will be added to - * another person's game), so they must be checked for last, after - * stripping all the possible prefixes and seeing if there's a real - * name in there. So we have to save the full original name. However, - * it's still possible to do things like "uncursed burnt Alaska", - * or worse yet, "2 burned 5 course meals", so we need to loop to - * strip off the prefixes again, this time stripping only the ones - * possible on food. - * We could get even more detailed so as to allow food names with - * prefixes that _are_ possible on food, so you could wish for - * "2 3 alarm chilis". Currently this isn't allowed; options.c - * automatically sticks 'candied' in front of such names. - */ - - char oclass; - char *un, *dn, *actualn; - const char *name=0; - - cnt = spe = spesgn = typ = very = rechrg = - blessed = uncursed = iscursed = - ispoisoned = isgreased = eroded = eroded2 = erodeproof = - halfeaten = islit = unlabeled = ishistoric = isdiluted = - trapped = 0; - tvariety = RANDOM_TIN; - mntmp = NON_PM; + register char *p; + register int i; + register struct obj *otmp; + int cnt, spe, spesgn, typ, very, rechrg; + int blessed, uncursed, iscursed, ispoisoned, isgreased; + int eroded, eroded2, erodeproof; + int halfeaten, mntmp, contents; + int islit, unlabeled, ishistoric, isdiluted, trapped; + int tmp, tinv, tvariety; + struct fruit *f; + int ftype = context.current_fruit; + char fruitbuf[BUFSZ]; + /* Fruits may not mess up the ability to wish for real objects (since + * you can leave a fruit in a bones file and it will be added to + * another person's game), so they must be checked for last, after + * stripping all the possible prefixes and seeing if there's a real + * name in there. So we have to save the full original name. However, + * it's still possible to do things like "uncursed burnt Alaska", + * or worse yet, "2 burned 5 course meals", so we need to loop to + * strip off the prefixes again, this time stripping only the ones + * possible on food. + * We could get even more detailed so as to allow food names with + * prefixes that _are_ possible on food, so you could wish for + * "2 3 alarm chilis". Currently this isn't allowed; options.c + * automatically sticks 'candied' in front of such names. + */ + + char oclass; + char *un, *dn, *actualn; + const char *name=0; + + cnt = spe = spesgn = typ = very = rechrg = + blessed = uncursed = iscursed = + ispoisoned = isgreased = eroded = eroded2 = erodeproof = + halfeaten = islit = unlabeled = ishistoric = isdiluted = + trapped = 0; + tvariety = RANDOM_TIN; + mntmp = NON_PM; #define UNDEFINED 0 #define EMPTY 1 #define SPINACH 2 - contents = UNDEFINED; - oclass = 0; - actualn = dn = un = 0; - - if (!bp) goto any; - /* first, remove extra whitespace they may have typed */ - (void)mungspaces(bp); - /* allow wishing for "nothing" to preserve wishless conduct... - [now requires "wand of nothing" if that's what was really wanted] */ - if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") || - !strcmpi(bp, "none")) return no_wish; - /* save the [nearly] unmodified choice string */ - Strcpy(fruitbuf, bp); - - for(;;) { - register int l; - - if (!bp || !*bp) goto any; - if (!strncmpi(bp, "an ", l=3) || - !strncmpi(bp, "a ", l=2)) { - cnt = 1; - } else if (!strncmpi(bp, "the ", l=4)) { - ; /* just increment `bp' by `l' below */ - } else if (!cnt && digit(*bp) && strcmp(bp, "0")) { - cnt = atoi(bp); - while(digit(*bp)) bp++; - while(*bp == ' ') bp++; - l = 0; - } else if (*bp == '+' || *bp == '-') { - spesgn = (*bp++ == '+') ? 1 : -1; - spe = atoi(bp); - while(digit(*bp)) bp++; - while(*bp == ' ') bp++; - l = 0; - } else if (!strncmpi(bp, "blessed ", l=8) || - !strncmpi(bp, "holy ", l=5)) { - blessed = 1; - } else if (!strncmpi(bp, "cursed ", l=7) || - !strncmpi(bp, "unholy ", l=7)) { - iscursed = 1; - } else if (!strncmpi(bp, "uncursed ", l=9)) { - uncursed = 1; - } else if (!strncmpi(bp, "rustproof ", l=10) || - !strncmpi(bp, "erodeproof ", l=11) || - !strncmpi(bp, "corrodeproof ", l=13) || - !strncmpi(bp, "fixed ", l=6) || - !strncmpi(bp, "fireproof ", l=10) || - !strncmpi(bp, "rotproof ", l=9)) { - erodeproof = 1; - } else if (!strncmpi(bp,"lit ", l=4) || - !strncmpi(bp,"burning ", l=8)) { - islit = 1; - } else if (!strncmpi(bp,"unlit ", l=6) || - !strncmpi(bp,"extinguished ", l=13)) { - islit = 0; - /* "unlabeled" and "blank" are synonymous */ - } else if (!strncmpi(bp,"unlabeled ", l=10) || - !strncmpi(bp,"unlabelled ", l=11) || - !strncmpi(bp,"blank ", l=6)) { - unlabeled = 1; - } else if(!strncmpi(bp, "poisoned ",l=9)) { - ispoisoned=1; - /* "trapped" recognized but not honored outside wizard mode */ - } else if(!strncmpi(bp, "trapped ",l=8)) { - trapped = 0; /* undo any previous "untrapped" */ - if (wizard) trapped = 1; - } else if(!strncmpi(bp, "untrapped ",l=10)) { - trapped = 2; /* not trapped */ - } else if(!strncmpi(bp, "greased ",l=8)) { - isgreased=1; - } else if (!strncmpi(bp, "very ", l=5)) { - /* very rusted very heavy iron ball */ - very = 1; - } else if (!strncmpi(bp, "thoroughly ", l=11)) { - very = 2; - } else if (!strncmpi(bp, "rusty ", l=6) || - !strncmpi(bp, "rusted ", l=7) || - !strncmpi(bp, "burnt ", l=6) || - !strncmpi(bp, "burned ", l=7)) { - eroded = 1 + very; - very = 0; - } else if (!strncmpi(bp, "corroded ", l=9) || - !strncmpi(bp, "rotted ", l=7)) { - eroded2 = 1 + very; - very = 0; - } else if (!strncmpi(bp, "partly eaten ", l=13) || - !strncmpi(bp, "partially eaten ", l=16)) { - halfeaten = 1; - } else if (!strncmpi(bp, "historic ", l=9)) { - ishistoric = 1; - } else if (!strncmpi(bp, "diluted ", l=8)) { - isdiluted = 1; - } else if(!strncmpi(bp, "empty ", l=6)) { - contents = EMPTY; - } else break; - bp += l; - } - if(!cnt) cnt = 1; /* %% what with "gems" etc. ? */ - if (strlen(bp) > 1) { - if ((p = rindex(bp, '(')) != 0) { - if (p > bp && p[-1] == ' ') p[-1] = 0; - else *p = 0; - p++; - if (!strcmpi(p, "lit)")) { - islit = 1; - } else { - spe = atoi(p); - while (digit(*p)) p++; - if (*p == ':') { - p++; - rechrg = spe; - spe = atoi(p); - while (digit(*p)) p++; - } - if (*p != ')') { - spe = rechrg = 0; - } else { - spesgn = 1; - p++; - if (*p) Strcat(bp, p); - } - } - } - } + contents = UNDEFINED; + oclass = 0; + actualn = dn = un = 0; + + if (!bp) goto any; + /* first, remove extra whitespace they may have typed */ + (void)mungspaces(bp); + /* allow wishing for "nothing" to preserve wishless conduct... + [now requires "wand of nothing" if that's what was really wanted] */ + if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") || + !strcmpi(bp, "none")) return no_wish; + /* save the [nearly] unmodified choice string */ + Strcpy(fruitbuf, bp); + + for(;;) { + register int l; + + if (!bp || !*bp) goto any; + if (!strncmpi(bp, "an ", l=3) || + !strncmpi(bp, "a ", l=2)) { + cnt = 1; + } else if (!strncmpi(bp, "the ", l=4)) { + ; /* just increment `bp' by `l' below */ + } else if (!cnt && digit(*bp) && strcmp(bp, "0")) { + cnt = atoi(bp); + while(digit(*bp)) bp++; + while(*bp == ' ') bp++; + l = 0; + } else if (*bp == '+' || *bp == '-') { + spesgn = (*bp++ == '+') ? 1 : -1; + spe = atoi(bp); + while(digit(*bp)) bp++; + while(*bp == ' ') bp++; + l = 0; + } else if (!strncmpi(bp, "blessed ", l=8) || + !strncmpi(bp, "holy ", l=5)) { + blessed = 1; + } else if (!strncmpi(bp, "cursed ", l=7) || + !strncmpi(bp, "unholy ", l=7)) { + iscursed = 1; + } else if (!strncmpi(bp, "uncursed ", l=9)) { + uncursed = 1; + } else if (!strncmpi(bp, "rustproof ", l=10) || + !strncmpi(bp, "erodeproof ", l=11) || + !strncmpi(bp, "corrodeproof ", l=13) || + !strncmpi(bp, "fixed ", l=6) || + !strncmpi(bp, "fireproof ", l=10) || + !strncmpi(bp, "rotproof ", l=9)) { + erodeproof = 1; + } else if (!strncmpi(bp,"lit ", l=4) || + !strncmpi(bp,"burning ", l=8)) { + islit = 1; + } else if (!strncmpi(bp,"unlit ", l=6) || + !strncmpi(bp,"extinguished ", l=13)) { + islit = 0; + /* "unlabeled" and "blank" are synonymous */ + } else if (!strncmpi(bp,"unlabeled ", l=10) || + !strncmpi(bp,"unlabelled ", l=11) || + !strncmpi(bp,"blank ", l=6)) { + unlabeled = 1; + } else if(!strncmpi(bp, "poisoned ",l=9)) { + ispoisoned=1; + /* "trapped" recognized but not honored outside wizard mode */ + } else if(!strncmpi(bp, "trapped ",l=8)) { + trapped = 0; /* undo any previous "untrapped" */ + if (wizard) trapped = 1; + } else if(!strncmpi(bp, "untrapped ",l=10)) { + trapped = 2; /* not trapped */ + } else if(!strncmpi(bp, "greased ",l=8)) { + isgreased=1; + } else if (!strncmpi(bp, "very ", l=5)) { + /* very rusted very heavy iron ball */ + very = 1; + } else if (!strncmpi(bp, "thoroughly ", l=11)) { + very = 2; + } else if (!strncmpi(bp, "rusty ", l=6) || + !strncmpi(bp, "rusted ", l=7) || + !strncmpi(bp, "burnt ", l=6) || + !strncmpi(bp, "burned ", l=7)) { + eroded = 1 + very; + very = 0; + } else if (!strncmpi(bp, "corroded ", l=9) || + !strncmpi(bp, "rotted ", l=7)) { + eroded2 = 1 + very; + very = 0; + } else if (!strncmpi(bp, "partly eaten ", l=13) || + !strncmpi(bp, "partially eaten ", l=16)) { + halfeaten = 1; + } else if (!strncmpi(bp, "historic ", l=9)) { + ishistoric = 1; + } else if (!strncmpi(bp, "diluted ", l=8)) { + isdiluted = 1; + } else if(!strncmpi(bp, "empty ", l=6)) { + contents = EMPTY; + } else break; + bp += l; + } + if(!cnt) cnt = 1; /* %% what with "gems" etc. ? */ + if (strlen(bp) > 1) { + if ((p = rindex(bp, '(')) != 0) { + if (p > bp && p[-1] == ' ') p[-1] = 0; + else *p = 0; + p++; + if (!strcmpi(p, "lit)")) { + islit = 1; + } else { + spe = atoi(p); + while (digit(*p)) p++; + if (*p == ':') { + p++; + rechrg = spe; + spe = atoi(p); + while (digit(*p)) p++; + } + if (*p != ')') { + spe = rechrg = 0; + } else { + spesgn = 1; + p++; + if (*p) Strcat(bp, p); + } + } + } + } /* otmp->spe is type schar; so we don't want spe to be any bigger or smaller. also, spe should always be positive -- some cheaters may try to confuse atoi() */ - if (spe < 0) { - spesgn = -1; /* cheaters get what they deserve */ - spe = abs(spe); - } - if (spe > SCHAR_LIM) - spe = SCHAR_LIM; - if (rechrg < 0 || rechrg > 7) rechrg = 7; /* recharge_limit */ - - /* now we have the actual name, as delivered by xname, say - green potions called whisky - scrolls labeled "QWERTY" - egg - fortune cookies - very heavy iron ball named hoei - wand of wishing - elven cloak - */ - if ((p = strstri(bp, " named ")) != 0) { - *p = 0; - name = p+7; - } - if ((p = strstri(bp, " called ")) != 0) { - *p = 0; - un = p+8; - /* "helmet called telepathy" is not "helmet" (a specific type) - * "shield called reflection" is not "shield" (a general type) - */ - for(i = 0; i < SIZE(o_ranges); i++) - if(!strcmpi(bp, o_ranges[i].name)) { - oclass = o_ranges[i].oclass; - goto srch; - } - } - if ((p = strstri(bp, " labeled ")) != 0) { - *p = 0; - dn = p+9; - } else if ((p = strstri(bp, " labelled ")) != 0) { - *p = 0; - dn = p+10; - } - if ((p = strstri(bp, " of spinach")) != 0) { - *p = 0; - contents = SPINACH; - } - - /* - Skip over "pair of ", "pairs of", "set of" and "sets of". - - Accept "3 pair of boots" as well as "3 pairs of boots". It is valid - English either way. See makeplural() for more on pair/pairs. - - We should only double count if the object in question is not - refered to as a "pair of". E.g. We should double if the player - types "pair of spears", but not if the player types "pair of - lenses". Luckily (?) all objects that are refered to as pairs - -- boots, gloves, and lenses -- are also not mergable, so cnt is - ignored anyway. - */ - if(!strncmpi(bp, "pair of ",8)) { - bp += 8; - cnt *= 2; - } else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) { - bp += 9; - cnt *= 2; - } else if (!strncmpi(bp, "set of ",7)) { - bp += 7; - } else if (!strncmpi(bp, "sets of ",8)) { - bp += 8; - } - - /* - * Find corpse type using "of" (figurine of an orc, tin of orc meat) - * Don't check if it's a wand or spellbook. - * (avoid "wand/finger of death" confusion). - */ - if (!strstri(bp, "wand ") - && !strstri(bp, "spellbook ") - && !strstri(bp, "finger ")) { - if (((p = strstri(bp, "tin of ")) != 0) && - (tmp = tin_variety_txt(p+7, &tinv)) && - (mntmp = name_to_mon(p+7+tmp)) >= LOW_PM) { - *(p+3) = 0; - tvariety = tinv; - } else if ((p = strstri(bp, " of ")) != 0 - && (mntmp = name_to_mon(p+4)) >= LOW_PM) - *p = 0; - } - /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */ - if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */ - if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */ - if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */ - if (strncmpi(bp, "master key", 10)) /* not the "master" rank */ - if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */ - if (mntmp < LOW_PM && strlen(bp) > 2 && - (mntmp = name_to_mon(bp)) >= LOW_PM) { - int mntmptoo, mntmplen; /* double check for rank title */ - char *obp = bp; - mntmptoo = title_to_mon(bp, (int *)0, &mntmplen); - bp += mntmp != mntmptoo ? (int)strlen(mons[mntmp].mname) : mntmplen; - if (*bp == ' ') bp++; - else if (!strncmpi(bp, "s ", 2)) bp += 2; - else if (!strncmpi(bp, "es ", 3)) bp += 3; - else if (!*bp && !actualn && !dn && !un && !oclass) { - /* no referent; they don't really mean a monster type */ - bp = obp; - mntmp = NON_PM; - } - } - - /* first change to singular if necessary */ - if (*bp) { - char *sng = makesingular(bp); - if (strcmp(bp, sng)) { - if (cnt == 1) cnt = 2; - Strcpy(bp, sng); - } - } - - /* Alternate spellings (pick-ax, silver sabre, &c) */ + if (spe < 0) { + spesgn = -1; /* cheaters get what they deserve */ + spe = abs(spe); + } + if (spe > SCHAR_LIM) + spe = SCHAR_LIM; + if (rechrg < 0 || rechrg > 7) rechrg = 7; /* recharge_limit */ + + /* now we have the actual name, as delivered by xname, say + green potions called whisky + scrolls labeled "QWERTY" + egg + fortune cookies + very heavy iron ball named hoei + wand of wishing + elven cloak + */ + if ((p = strstri(bp, " named ")) != 0) { + *p = 0; + name = p+7; + } + if ((p = strstri(bp, " called ")) != 0) { + *p = 0; + un = p+8; + /* "helmet called telepathy" is not "helmet" (a specific type) + * "shield called reflection" is not "shield" (a general type) + */ + for(i = 0; i < SIZE(o_ranges); i++) + if(!strcmpi(bp, o_ranges[i].name)) { + oclass = o_ranges[i].oclass; + goto srch; + } + } + if ((p = strstri(bp, " labeled ")) != 0) { + *p = 0; + dn = p+9; + } else if ((p = strstri(bp, " labelled ")) != 0) { + *p = 0; + dn = p+10; + } + if ((p = strstri(bp, " of spinach")) != 0) { + *p = 0; + contents = SPINACH; + } + + /* + Skip over "pair of ", "pairs of", "set of" and "sets of". + + Accept "3 pair of boots" as well as "3 pairs of boots". It is valid + English either way. See makeplural() for more on pair/pairs. + + We should only double count if the object in question is not + refered to as a "pair of". E.g. We should double if the player + types "pair of spears", but not if the player types "pair of + lenses". Luckily (?) all objects that are refered to as pairs + -- boots, gloves, and lenses -- are also not mergable, so cnt is + ignored anyway. + */ + if(!strncmpi(bp, "pair of ",8)) { + bp += 8; + cnt *= 2; + } else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) { + bp += 9; + cnt *= 2; + } else if (!strncmpi(bp, "set of ",7)) { + bp += 7; + } else if (!strncmpi(bp, "sets of ",8)) { + bp += 8; + } + + /* + * Find corpse type using "of" (figurine of an orc, tin of orc meat) + * Don't check if it's a wand or spellbook. + * (avoid "wand/finger of death" confusion). + */ + if (!strstri(bp, "wand ") + && !strstri(bp, "spellbook ") + && !strstri(bp, "finger ")) { + if (((p = strstri(bp, "tin of ")) != 0) && + (tmp = tin_variety_txt(p+7, &tinv)) && + (mntmp = name_to_mon(p+7+tmp)) >= LOW_PM) { + *(p+3) = 0; + tvariety = tinv; + } else if ((p = strstri(bp, " of ")) != 0 + && (mntmp = name_to_mon(p+4)) >= LOW_PM) + *p = 0; + } + /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */ + if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */ + if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */ + if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */ + if (strncmpi(bp, "master key", 10)) /* not the "master" rank */ + if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */ + if (mntmp < LOW_PM && strlen(bp) > 2 && + (mntmp = name_to_mon(bp)) >= LOW_PM) { + int mntmptoo, mntmplen; /* double check for rank title */ + char *obp = bp; + mntmptoo = title_to_mon(bp, (int *)0, &mntmplen); + bp += mntmp != mntmptoo ? (int)strlen(mons[mntmp].mname) : mntmplen; + if (*bp == ' ') bp++; + else if (!strncmpi(bp, "s ", 2)) bp += 2; + else if (!strncmpi(bp, "es ", 3)) bp += 3; + else if (!*bp && !actualn && !dn && !un && !oclass) { + /* no referent; they don't really mean a monster type */ + bp = obp; + mntmp = NON_PM; + } + } + + /* first change to singular if necessary */ + if (*bp) { + char *sng = makesingular(bp); + if (strcmp(bp, sng)) { + if (cnt == 1) cnt = 2; + Strcpy(bp, sng); + } + } + + /* Alternate spellings (pick-ax, silver sabre, &c) */ { - struct alt_spellings *as = spellings; - - while (as->sp) { - if (fuzzymatch(bp, as->sp, " -", TRUE)) { - typ = as->ob; - goto typfnd; - } - as++; - } - /* can't use spellings list for this one due to shuffling */ - if (!strncmpi(bp, "grey spell", 10)) - *(bp + 2) = 'a'; - - if ((p = strstri(bp, "armour")) != 0) { - /* skip past "armo", then copy remainer beyond "u" */ - p += 4; - while ((*p = *(p + 1)) != '\0') ++p; /* self terminating */ - } - } - - /* dragon scales - assumes order of dragons */ - if(!strcmpi(bp, "scales") && - mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) { - typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON; - mntmp = NON_PM; /* no monster */ - goto typfnd; - } - - p = eos(bp); - if(!BSTRCMPI(bp, p-10, "holy water")) { - typ = POT_WATER; - if ((p-bp) >= 12 && *(p-12) == 'u') - iscursed = 1; /* unholy water */ - else blessed = 1; - goto typfnd; - } - if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) { - typ = SCR_BLANK_PAPER; - goto typfnd; - } - if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) { - typ = SPE_BLANK_PAPER; - goto typfnd; - } - /* - * NOTE: Gold pieces are handled as objects nowadays, and therefore - * this section should probably be reconsidered as well as the entire - * gold/money concept. Maybe we want to add other monetary units as - * well in the future. (TH) - */ - if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") || - !strcmpi(bp, "gold") || !strcmpi(bp, "money") || - !strcmpi(bp, "coin") || *bp == GOLD_SYM) { - if (cnt > 5000 && !wizard) cnt = 5000; - else if (cnt < 1) cnt = 1; - otmp = mksobj(GOLD_PIECE, FALSE, FALSE); - otmp->quan = (long) cnt; - otmp->owt = weight(otmp); - context.botl = 1; - return otmp; - } - - /* check for single character object class code ("/" for wand, &c) */ - if (strlen(bp) == 1 && - (i = def_char_to_objclass(*bp)) < MAXOCLASSES && - i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) { - oclass = i; - goto any; - } - - /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */ - /* false hits on, e.g., rings for "ring mail". */ - if(strncmpi(bp, "enchant ", 8) && - strncmpi(bp, "destroy ", 8) && - strncmpi(bp, "detect food", 11) && - strncmpi(bp, "food detection", 14) && - strncmpi(bp, "ring mail", 9) && - strncmpi(bp, "studded leather armor", 21) && - strncmpi(bp, "leather armor", 13) && - strncmpi(bp, "tooled horn", 11) && - strncmpi(bp, "food ration", 11) && - strncmpi(bp, "meat ring", 9) - ) - for (i = 0; i < (int)(sizeof wrpsym); i++) { - register int j = strlen(wrp[i]); - if(!strncmpi(bp, wrp[i], j)){ - oclass = wrpsym[i]; - if(oclass != AMULET_CLASS) { - bp += j; - if(!strncmpi(bp, " of ", 4)) actualn = bp+4; - /* else if(*bp) ?? */ - } else - actualn = bp; - goto srch; - } - if(!BSTRCMPI(bp, p-j, wrp[i])){ - oclass = wrpsym[i]; - p -= j; - *p = 0; - if(p > bp && p[-1] == ' ') p[-1] = 0; - actualn = dn = bp; - goto srch; - } - } - - /* Wishing in wizard mode can create traps and furniture. - * Part I: distinguish between trap and object for the two - * types of traps which have corresponding objects: bear trap - * and land mine. "beartrap" (object) and "bear trap" (trap) - * have a difference in spelling which we used to exploit by - * adding a special case in wishymatch(), but "land mine" is - * spelled the same either way so needs different handing. - * Since we need something else for land mine, we've dropped - * the bear trap hack so that both are handled exactly the - * same. To get an armed trap instead of a disarmed object, - * the player can prefix either the object name or the trap - * name with "trapped " (which ordinarily applies to chests - * and tins), or append something--anything at all except for - * " object", but " trap" is suggested--to either the trap - * name or the object name. - */ - if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) { - boolean beartrap = (lowc(*bp) == 'b'); - char *zp = bp + 4; /* skip "bear"/"land" */ - - if (*zp == ' ') ++zp; /* embedded space is optional */ - if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) { - zp += 4; - if (trapped == 2 || !strcmpi(zp, " object")) { - /* "untrapped " or " object" */ - typ = beartrap ? BEARTRAP : LAND_MINE; - goto typfnd; - } else if (trapped == 1 || *zp != '\0') { - /* "trapped " or " trap" (actually "*") */ - int idx = trap_to_defsym(beartrap ? BEAR_TRAP : LANDMINE); - - /* use canonical trap spelling, skip object matching */ - Strcpy(bp, defsyms[idx].explanation); - goto wiztrap; - } - /* [no prefix or suffix; we're going to end up matching - the object name and getting a disarmed trap object] */ - } - } + struct alt_spellings *as = spellings; + + while (as->sp) { + if (fuzzymatch(bp, as->sp, " -", TRUE)) { + typ = as->ob; + goto typfnd; + } + as++; + } + /* can't use spellings list for this one due to shuffling */ + if (!strncmpi(bp, "grey spell", 10)) + *(bp + 2) = 'a'; + + if ((p = strstri(bp, "armour")) != 0) { + /* skip past "armo", then copy remainer beyond "u" */ + p += 4; + while ((*p = *(p + 1)) != '\0') ++p; /* self terminating */ + } + } + + /* dragon scales - assumes order of dragons */ + if(!strcmpi(bp, "scales") && + mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) { + typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON; + mntmp = NON_PM; /* no monster */ + goto typfnd; + } + + p = eos(bp); + if(!BSTRCMPI(bp, p-10, "holy water")) { + typ = POT_WATER; + if ((p-bp) >= 12 && *(p-12) == 'u') + iscursed = 1; /* unholy water */ + else blessed = 1; + goto typfnd; + } + if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) { + typ = SCR_BLANK_PAPER; + goto typfnd; + } + if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) { + typ = SPE_BLANK_PAPER; + goto typfnd; + } + /* + * NOTE: Gold pieces are handled as objects nowadays, and therefore + * this section should probably be reconsidered as well as the entire + * gold/money concept. Maybe we want to add other monetary units as + * well in the future. (TH) + */ + if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") || + !strcmpi(bp, "gold") || !strcmpi(bp, "money") || + !strcmpi(bp, "coin") || *bp == GOLD_SYM) { + if (cnt > 5000 && !wizard) cnt = 5000; + else if (cnt < 1) cnt = 1; + otmp = mksobj(GOLD_PIECE, FALSE, FALSE); + otmp->quan = (long) cnt; + otmp->owt = weight(otmp); + context.botl = 1; + return otmp; + } + + /* check for single character object class code ("/" for wand, &c) */ + if (strlen(bp) == 1 && + (i = def_char_to_objclass(*bp)) < MAXOCLASSES && + i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) { + oclass = i; + goto any; + } + + /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */ + /* false hits on, e.g., rings for "ring mail". */ + if(strncmpi(bp, "enchant ", 8) && + strncmpi(bp, "destroy ", 8) && + strncmpi(bp, "detect food", 11) && + strncmpi(bp, "food detection", 14) && + strncmpi(bp, "ring mail", 9) && + strncmpi(bp, "studded leather armor", 21) && + strncmpi(bp, "leather armor", 13) && + strncmpi(bp, "tooled horn", 11) && + strncmpi(bp, "food ration", 11) && + strncmpi(bp, "meat ring", 9) + ) + for (i = 0; i < (int)(sizeof wrpsym); i++) { + register int j = strlen(wrp[i]); + if(!strncmpi(bp, wrp[i], j)){ + oclass = wrpsym[i]; + if(oclass != AMULET_CLASS) { + bp += j; + if(!strncmpi(bp, " of ", 4)) actualn = bp+4; + /* else if(*bp) ?? */ + } else + actualn = bp; + goto srch; + } + if(!BSTRCMPI(bp, p-j, wrp[i])){ + oclass = wrpsym[i]; + p -= j; + *p = 0; + if(p > bp && p[-1] == ' ') p[-1] = 0; + actualn = dn = bp; + goto srch; + } + } + + /* Wishing in wizard mode can create traps and furniture. + * Part I: distinguish between trap and object for the two + * types of traps which have corresponding objects: bear trap + * and land mine. "beartrap" (object) and "bear trap" (trap) + * have a difference in spelling which we used to exploit by + * adding a special case in wishymatch(), but "land mine" is + * spelled the same either way so needs different handing. + * Since we need something else for land mine, we've dropped + * the bear trap hack so that both are handled exactly the + * same. To get an armed trap instead of a disarmed object, + * the player can prefix either the object name or the trap + * name with "trapped " (which ordinarily applies to chests + * and tins), or append something--anything at all except for + * " object", but " trap" is suggested--to either the trap + * name or the object name. + */ + if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) { + boolean beartrap = (lowc(*bp) == 'b'); + char *zp = bp + 4; /* skip "bear"/"land" */ + + if (*zp == ' ') ++zp; /* embedded space is optional */ + if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) { + zp += 4; + if (trapped == 2 || !strcmpi(zp, " object")) { + /* "untrapped " or " object" */ + typ = beartrap ? BEARTRAP : LAND_MINE; + goto typfnd; + } else if (trapped == 1 || *zp != '\0') { + /* "trapped " or " trap" (actually "*") */ + int idx = trap_to_defsym(beartrap ? BEAR_TRAP : LANDMINE); + + /* use canonical trap spelling, skip object matching */ + Strcpy(bp, defsyms[idx].explanation); + goto wiztrap; + } + /* [no prefix or suffix; we're going to end up matching + the object name and getting a disarmed trap object] */ + } + } retry: - /* "grey stone" check must be before general "stone" */ - for (i = 0; i < SIZE(o_ranges); i++) - if(!strcmpi(bp, o_ranges[i].name)) { - typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range); - goto typfnd; - } - - if (!BSTRCMPI(bp, p-6, " stone")) { - p[-6] = 0; - oclass = GEM_CLASS; - dn = actualn = bp; - goto srch; - } else if (!strcmpi(bp, "looking glass")) { - ; /* avoid false hit on "* glass" */ - } else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) { - register char *g = bp; - if (strstri(g, "broken")) return (struct obj *)0; - if (!strncmpi(g, "worthless ", 10)) g += 10; - if (!strncmpi(g, "piece of ", 9)) g += 9; - if (!strncmpi(g, "colored ", 8)) g += 8; - else if (!strncmpi(g, "coloured ", 9)) g += 9; - if (!strcmpi(g, "glass")) { /* choose random color */ - /* 9 different kinds */ - typ = LAST_GEM + rnd(9); - if (objects[typ].oc_class == GEM_CLASS) goto typfnd; - else typ = 0; /* somebody changed objects[]? punt */ - } else { /* try to construct canonical form */ - char tbuf[BUFSZ]; - Strcpy(tbuf, "worthless piece of "); - Strcat(tbuf, g); /* assume it starts with the color */ - Strcpy(bp, tbuf); - } - } - - actualn = bp; - if (!dn) dn = actualn; /* ex. "skull cap" */ + /* "grey stone" check must be before general "stone" */ + for (i = 0; i < SIZE(o_ranges); i++) + if(!strcmpi(bp, o_ranges[i].name)) { + typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range); + goto typfnd; + } + + if (!BSTRCMPI(bp, p-6, " stone")) { + p[-6] = 0; + oclass = GEM_CLASS; + dn = actualn = bp; + goto srch; + } else if (!strcmpi(bp, "looking glass")) { + ; /* avoid false hit on "* glass" */ + } else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) { + register char *g = bp; + if (strstri(g, "broken")) return (struct obj *)0; + if (!strncmpi(g, "worthless ", 10)) g += 10; + if (!strncmpi(g, "piece of ", 9)) g += 9; + if (!strncmpi(g, "colored ", 8)) g += 8; + else if (!strncmpi(g, "coloured ", 9)) g += 9; + if (!strcmpi(g, "glass")) { /* choose random color */ + /* 9 different kinds */ + typ = LAST_GEM + rnd(9); + if (objects[typ].oc_class == GEM_CLASS) goto typfnd; + else typ = 0; /* somebody changed objects[]? punt */ + } else { /* try to construct canonical form */ + char tbuf[BUFSZ]; + Strcpy(tbuf, "worthless piece of "); + Strcat(tbuf, g); /* assume it starts with the color */ + Strcpy(bp, tbuf); + } + } + + actualn = bp; + if (!dn) dn = actualn; /* ex. "skull cap" */ srch: - /* check real names of gems first */ - if(!oclass && actualn) { - for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) { - register const char *zn; - - if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) { - typ = i; - goto typfnd; - } - } - } - i = oclass ? bases[(int)oclass] : 1; - while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){ - register const char *zn; - - if (actualn && (zn = OBJ_NAME(objects[i])) != 0 && - wishymatch(actualn, zn, TRUE)) { - typ = i; - goto typfnd; - } - if (dn && (zn = OBJ_DESCR(objects[i])) != 0 && - wishymatch(dn, zn, FALSE)) { - /* don't match extra descriptions (w/o real name) */ - if (!OBJ_NAME(objects[i])) return (struct obj *)0; - typ = i; - goto typfnd; - } - if (un && (zn = objects[i].oc_uname) != 0 && - wishymatch(un, zn, FALSE)) { - typ = i; - goto typfnd; - } - i++; - } - if (actualn) { - struct Jitem *j = Japanese_items; - while(j->item) { - if (actualn && !strcmpi(actualn, j->name)) { - typ = j->item; - goto typfnd; - } - j++; - } - } - /* if we've stripped off "armor" and failed to match anything - in objects[], append "mail" and try again to catch misnamed - requests like "plate armor" and "yellow dragon scale armor" */ - if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) { - /* modifying bp's string is ok; we're about to resort - to random armor if this also fails to match anything */ - Strcat(bp, " mail"); - goto retry; - } - if (!strcmpi(bp, "spinach")) { - contents = SPINACH; - typ = TIN; - goto typfnd; - } - /* Note: not strcmpi. 2 fruits, one capital, one not, are possible. - Also not strncmp. We used to ignore trailing text with it, but - that resulted in "grapefruit" matching "grape" if the latter came - earlier than the former in the fruit list. */ - { - char *fp; - int l, cntf; - int blessedf, iscursedf, uncursedf, halfeatenf; - - blessedf = iscursedf = uncursedf = halfeatenf = 0; - cntf = 0; - - fp = fruitbuf; - for(;;) { - if (!fp || !*fp) break; - if (!strncmpi(fp, "an ", l=3) || - !strncmpi(fp, "a ", l=2)) { - cntf = 1; - } else if (!cntf && digit(*fp)) { - cntf = atoi(fp); - while(digit(*fp)) fp++; - while(*fp == ' ') fp++; - l = 0; - } else if (!strncmpi(fp, "blessed ", l=8)) { - blessedf = 1; - } else if (!strncmpi(fp, "cursed ", l=7)) { - iscursedf = 1; - } else if (!strncmpi(fp, "uncursed ", l=9)) { - uncursedf = 1; - } else if (!strncmpi(fp, "partly eaten ", l=13) || - !strncmpi(fp, "partially eaten ", l=16)) { - halfeatenf = 1; - } else break; - fp += l; - } - - for(f=ffruit; f; f = f->nextf) { - /* match type: 0=none, 1=exact, 2=singular, 3=plural */ - int ftyp = 0; - - if (!strcmp(fp, f->fname)) ftyp = 1; - else if (!strcmp(fp, makesingular(f->fname))) ftyp = 2; - else if (!strcmp(fp, makeplural(f->fname))) ftyp = 3; - if (ftyp) { - typ = SLIME_MOLD; - blessed = blessedf; - iscursed = iscursedf; - uncursed = uncursedf; - halfeaten = halfeatenf; - /* adjust count if user explicitly asked for - singular amount (can't happen unless fruit - has been given an already pluralized name) - or for plural amount */ - if (ftyp == 2 && !cntf) cntf = 1; - else if (ftyp == 3 && !cntf) cntf = 2; - cnt = cntf; - ftype = f->fid; - goto typfnd; - } - } - } - - if(!oclass && actualn) { - short objtyp; - - /* Perhaps it's an artifact specified by name, not type */ - name = artifact_name(actualn, &objtyp); - if(name) { - typ = objtyp; - goto typfnd; - } - } - /* Let wizards wish for traps and furniture. - * Must come after objects check so wizards can still wish for - * trap objects like beartraps. - * Disallow such topology tweaks for WIZKIT startup wishes. - */ + /* check real names of gems first */ + if(!oclass && actualn) { + for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) { + register const char *zn; + + if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) { + typ = i; + goto typfnd; + } + } + } + i = oclass ? bases[(int)oclass] : 1; + while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){ + register const char *zn; + + if (actualn && (zn = OBJ_NAME(objects[i])) != 0 && + wishymatch(actualn, zn, TRUE)) { + typ = i; + goto typfnd; + } + if (dn && (zn = OBJ_DESCR(objects[i])) != 0 && + wishymatch(dn, zn, FALSE)) { + /* don't match extra descriptions (w/o real name) */ + if (!OBJ_NAME(objects[i])) return (struct obj *)0; + typ = i; + goto typfnd; + } + if (un && (zn = objects[i].oc_uname) != 0 && + wishymatch(un, zn, FALSE)) { + typ = i; + goto typfnd; + } + i++; + } + if (actualn) { + struct Jitem *j = Japanese_items; + while(j->item) { + if (actualn && !strcmpi(actualn, j->name)) { + typ = j->item; + goto typfnd; + } + j++; + } + } + /* if we've stripped off "armor" and failed to match anything + in objects[], append "mail" and try again to catch misnamed + requests like "plate armor" and "yellow dragon scale armor" */ + if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) { + /* modifying bp's string is ok; we're about to resort + to random armor if this also fails to match anything */ + Strcat(bp, " mail"); + goto retry; + } + if (!strcmpi(bp, "spinach")) { + contents = SPINACH; + typ = TIN; + goto typfnd; + } + /* Note: not strcmpi. 2 fruits, one capital, one not, are possible. + Also not strncmp. We used to ignore trailing text with it, but + that resulted in "grapefruit" matching "grape" if the latter came + earlier than the former in the fruit list. */ + { + char *fp; + int l, cntf; + int blessedf, iscursedf, uncursedf, halfeatenf; + + blessedf = iscursedf = uncursedf = halfeatenf = 0; + cntf = 0; + + fp = fruitbuf; + for(;;) { + if (!fp || !*fp) break; + if (!strncmpi(fp, "an ", l=3) || + !strncmpi(fp, "a ", l=2)) { + cntf = 1; + } else if (!cntf && digit(*fp)) { + cntf = atoi(fp); + while(digit(*fp)) fp++; + while(*fp == ' ') fp++; + l = 0; + } else if (!strncmpi(fp, "blessed ", l=8)) { + blessedf = 1; + } else if (!strncmpi(fp, "cursed ", l=7)) { + iscursedf = 1; + } else if (!strncmpi(fp, "uncursed ", l=9)) { + uncursedf = 1; + } else if (!strncmpi(fp, "partly eaten ", l=13) || + !strncmpi(fp, "partially eaten ", l=16)) { + halfeatenf = 1; + } else break; + fp += l; + } + + for(f=ffruit; f; f = f->nextf) { + /* match type: 0=none, 1=exact, 2=singular, 3=plural */ + int ftyp = 0; + + if (!strcmp(fp, f->fname)) ftyp = 1; + else if (!strcmp(fp, makesingular(f->fname))) ftyp = 2; + else if (!strcmp(fp, makeplural(f->fname))) ftyp = 3; + if (ftyp) { + typ = SLIME_MOLD; + blessed = blessedf; + iscursed = iscursedf; + uncursed = uncursedf; + halfeaten = halfeatenf; + /* adjust count if user explicitly asked for + singular amount (can't happen unless fruit + has been given an already pluralized name) + or for plural amount */ + if (ftyp == 2 && !cntf) cntf = 1; + else if (ftyp == 3 && !cntf) cntf = 2; + cnt = cntf; + ftype = f->fid; + goto typfnd; + } + } + } + + if(!oclass && actualn) { + short objtyp; + + /* Perhaps it's an artifact specified by name, not type */ + name = artifact_name(actualn, &objtyp); + if(name) { + typ = objtyp; + goto typfnd; + } + } + /* Let wizards wish for traps and furniture. + * Must come after objects check so wizards can still wish for + * trap objects like beartraps. + * Disallow such topology tweaks for WIZKIT startup wishes. + */ wiztrap: - if (wizard && !program_state.wizkit_wishing) { - struct rm *lev; - int trap, x = u.ux, y = u.uy; - - for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) { - struct trap *t; - const char *tname; - - tname = defsyms[trap_to_defsym(trap)].explanation; - if (strncmpi(tname, bp, strlen(tname))) continue; - /* found it; avoid stupid mistakes */ - if ((trap == TRAPDOOR || trap == HOLE) && - !Can_fall_thru(&u.uz)) trap = ROCKTRAP; - if ((t = maketrap(x, y, trap)) != 0) { - trap = t->ttyp; - tname = defsyms[trap_to_defsym(trap)].explanation; - pline("%s%s.", An(tname), - (trap != MAGIC_PORTAL) ? "" : " to nowhere"); - } else - pline("Creation of %s failed.", an(tname)); - return(&zeroobj); - } - - /* furniture and terrain */ - lev = &levl[x][y]; - p = eos(bp); - if (!BSTRCMPI(bp, p-8, "fountain")) { - lev->typ = FOUNTAIN; - level.flags.nfountains++; - if(!strncmpi(bp, "magic ", 6)) lev->blessedftn = 1; - pline("A %sfountain.", lev->blessedftn ? "magic " : ""); - newsym(x, y); - return(&zeroobj); - } - if (!BSTRCMPI(bp, p-6, "throne")) { - lev->typ = THRONE; - pline("A throne."); - newsym(x, y); - return(&zeroobj); - } - if (!BSTRCMPI(bp, p-4, "sink")) { - lev->typ = SINK; - level.flags.nsinks++; - pline("A sink."); - newsym(x, y); - return &zeroobj; - } - /* ("water" matches "potion of water" rather than terrain) */ - if (!BSTRCMPI(bp, p-4, "pool") || !BSTRCMPI(bp, p-4, "moat")) { - lev->typ = !BSTRCMPI(bp, p-4, "pool") ? POOL : MOAT; - del_engr_at(x, y); - pline("A %s.", (lev->typ == POOL) ? "pool" : "moat"); - /* Must manually make kelp! */ - water_damage_chain(level.objects[x][y], TRUE); - newsym(x, y); - return &zeroobj; - } - if (!BSTRCMPI(bp, p-4, "lava")) { /* also matches "molten lava" */ - lev->typ = LAVAPOOL; - del_engr_at(x, y); - pline("A pool of molten lava."); - if (!(Levitation || Flying)) (void) lava_effects(); - newsym(x, y); - return &zeroobj; - } - - if (!BSTRCMPI(bp, p-5, "altar")) { - aligntyp al; - - lev->typ = ALTAR; - if(!strncmpi(bp, "chaotic ", 8)) - al = A_CHAOTIC; - else if(!strncmpi(bp, "neutral ", 8)) - al = A_NEUTRAL; - else if(!strncmpi(bp, "lawful ", 7)) - al = A_LAWFUL; - else if(!strncmpi(bp, "unaligned ", 10)) - al = A_NONE; - else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */ - al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1; - lev->altarmask = Align2amask(al); - pline("%s altar.", An(align_str(al))); - newsym(x, y); - return(&zeroobj); - } - - if (!BSTRCMPI(bp, p-5, "grave") || - !BSTRCMPI(bp, p-9, "headstone")) { - make_grave(x, y, (char *)0); - pline("%s.", IS_GRAVE(lev->typ) ? "A grave" : - "Can't place a grave here"); - newsym(x, y); - return(&zeroobj); - } - - if (!BSTRCMPI(bp, p-4, "tree")) { - lev->typ = TREE; - pline("A tree."); - newsym(x, y); - block_point(x, y); - return &zeroobj; - } - - if (!BSTRCMPI(bp, p-4, "bars")) { - lev->typ = IRONBARS; - pline("Iron bars."); - newsym(x, y); - return &zeroobj; - } - } - - if(!oclass) return((struct obj *)0); + if (wizard && !program_state.wizkit_wishing) { + struct rm *lev; + int trap, x = u.ux, y = u.uy; + + for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) { + struct trap *t; + const char *tname; + + tname = defsyms[trap_to_defsym(trap)].explanation; + if (strncmpi(tname, bp, strlen(tname))) continue; + /* found it; avoid stupid mistakes */ + if ((trap == TRAPDOOR || trap == HOLE) && + !Can_fall_thru(&u.uz)) trap = ROCKTRAP; + if ((t = maketrap(x, y, trap)) != 0) { + trap = t->ttyp; + tname = defsyms[trap_to_defsym(trap)].explanation; + pline("%s%s.", An(tname), + (trap != MAGIC_PORTAL) ? "" : " to nowhere"); + } else + pline("Creation of %s failed.", an(tname)); + return(&zeroobj); + } + + /* furniture and terrain */ + lev = &levl[x][y]; + p = eos(bp); + if (!BSTRCMPI(bp, p-8, "fountain")) { + lev->typ = FOUNTAIN; + level.flags.nfountains++; + if(!strncmpi(bp, "magic ", 6)) lev->blessedftn = 1; + pline("A %sfountain.", lev->blessedftn ? "magic " : ""); + newsym(x, y); + return(&zeroobj); + } + if (!BSTRCMPI(bp, p-6, "throne")) { + lev->typ = THRONE; + pline("A throne."); + newsym(x, y); + return(&zeroobj); + } + if (!BSTRCMPI(bp, p-4, "sink")) { + lev->typ = SINK; + level.flags.nsinks++; + pline("A sink."); + newsym(x, y); + return &zeroobj; + } + /* ("water" matches "potion of water" rather than terrain) */ + if (!BSTRCMPI(bp, p-4, "pool") || !BSTRCMPI(bp, p-4, "moat")) { + lev->typ = !BSTRCMPI(bp, p-4, "pool") ? POOL : MOAT; + del_engr_at(x, y); + pline("A %s.", (lev->typ == POOL) ? "pool" : "moat"); + /* Must manually make kelp! */ + water_damage_chain(level.objects[x][y], TRUE); + newsym(x, y); + return &zeroobj; + } + if (!BSTRCMPI(bp, p-4, "lava")) { /* also matches "molten lava" */ + lev->typ = LAVAPOOL; + del_engr_at(x, y); + pline("A pool of molten lava."); + if (!(Levitation || Flying)) (void) lava_effects(); + newsym(x, y); + return &zeroobj; + } + + if (!BSTRCMPI(bp, p-5, "altar")) { + aligntyp al; + + lev->typ = ALTAR; + if(!strncmpi(bp, "chaotic ", 8)) + al = A_CHAOTIC; + else if(!strncmpi(bp, "neutral ", 8)) + al = A_NEUTRAL; + else if(!strncmpi(bp, "lawful ", 7)) + al = A_LAWFUL; + else if(!strncmpi(bp, "unaligned ", 10)) + al = A_NONE; + else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */ + al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1; + lev->altarmask = Align2amask(al); + pline("%s altar.", An(align_str(al))); + newsym(x, y); + return(&zeroobj); + } + + if (!BSTRCMPI(bp, p-5, "grave") || + !BSTRCMPI(bp, p-9, "headstone")) { + make_grave(x, y, (char *)0); + pline("%s.", IS_GRAVE(lev->typ) ? "A grave" : + "Can't place a grave here"); + newsym(x, y); + return(&zeroobj); + } + + if (!BSTRCMPI(bp, p-4, "tree")) { + lev->typ = TREE; + pline("A tree."); + newsym(x, y); + block_point(x, y); + return &zeroobj; + } + + if (!BSTRCMPI(bp, p-4, "bars")) { + lev->typ = IRONBARS; + pline("Iron bars."); + newsym(x, y); + return &zeroobj; + } + } + + if(!oclass) return((struct obj *)0); any: - if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))]; + if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))]; typfnd: - if (typ) oclass = objects[typ].oc_class; - - /* handle some objects that are only allowed in wizard mode */ - if (typ && !wizard) { - switch (typ) { - case AMULET_OF_YENDOR: - typ = FAKE_AMULET_OF_YENDOR; - break; - case CANDELABRUM_OF_INVOCATION: - typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE); - break; - case BELL_OF_OPENING: - typ = BELL; - break; - case SPE_BOOK_OF_THE_DEAD: - typ = SPE_BLANK_PAPER; - break; - case MAGIC_LAMP: - typ = OIL_LAMP; - break; - default: - /* catch any other non-wishable objects (venom) */ - if (objects[typ].oc_nowish) return ((struct obj *)0); - break; - } - } - - /* - * Create the object, then fine-tune it. - */ - otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE); - typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */ - - if (islit && - (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN || - Is_candle(otmp) || typ == POT_OIL)) { - place_object(otmp, u.ux, u.uy); /* make it viable light source */ - begin_burn(otmp, FALSE); - obj_extract_self(otmp); /* now release it for caller's use */ - } - - /* if player specified a reasonable count, maybe honor it */ - if (cnt > 0 && objects[typ].oc_merge && - (wizard || cnt < rnd(6) || - (cnt <= 7 && Is_candle(otmp)) || - (cnt <= 20 && - ((oclass == WEAPON_CLASS && is_ammo(otmp)) - || typ == ROCK || is_missile(otmp))))) - otmp->quan = (long) cnt; - - if (oclass == VENOM_CLASS) otmp->spe = 1; - - if (spesgn == 0) { - spe = otmp->spe; - } else if (wizard) { - ; /* no alteration to spe */ - } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS || - is_weptool(otmp) || - (oclass==RING_CLASS && objects[typ].oc_charged)) { - if(spe > rnd(5) && spe > otmp->spe) spe = 0; - if(spe > 2 && Luck < 0) spesgn = -1; - } else { - if (oclass == WAND_CLASS) { - if (spe > 1 && spesgn == -1) spe = 1; - } else { - if (spe > 0 && spesgn == -1) spe = 0; - } - if (spe > otmp->spe) spe = otmp->spe; - } - - if (spesgn == -1) spe = -spe; - - /* set otmp->spe. This may, or may not, use spe... */ - switch (typ) { - case TIN: if (contents==EMPTY) { - otmp->corpsenm = NON_PM; - otmp->spe = 0; - } else if (contents==SPINACH) { - otmp->corpsenm = NON_PM; - otmp->spe = 1; - } - break; - case SLIME_MOLD: otmp->spe = ftype; - /* Fall through */ - case SKELETON_KEY: case CHEST: case LARGE_BOX: - case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE: - /* otmp->cobj already done in mksobj() */ - break; + if (typ) oclass = objects[typ].oc_class; + + /* handle some objects that are only allowed in wizard mode */ + if (typ && !wizard) { + switch (typ) { + case AMULET_OF_YENDOR: + typ = FAKE_AMULET_OF_YENDOR; + break; + case CANDELABRUM_OF_INVOCATION: + typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE); + break; + case BELL_OF_OPENING: + typ = BELL; + break; + case SPE_BOOK_OF_THE_DEAD: + typ = SPE_BLANK_PAPER; + break; + case MAGIC_LAMP: + typ = OIL_LAMP; + break; + default: + /* catch any other non-wishable objects (venom) */ + if (objects[typ].oc_nowish) return ((struct obj *)0); + break; + } + } + + /* + * Create the object, then fine-tune it. + */ + otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE); + typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */ + + if (islit && + (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN || + Is_candle(otmp) || typ == POT_OIL)) { + place_object(otmp, u.ux, u.uy); /* make it viable light source */ + begin_burn(otmp, FALSE); + obj_extract_self(otmp); /* now release it for caller's use */ + } + + /* if player specified a reasonable count, maybe honor it */ + if (cnt > 0 && objects[typ].oc_merge && + (wizard || cnt < rnd(6) || + (cnt <= 7 && Is_candle(otmp)) || + (cnt <= 20 && + ((oclass == WEAPON_CLASS && is_ammo(otmp)) + || typ == ROCK || is_missile(otmp))))) + otmp->quan = (long) cnt; + + if (oclass == VENOM_CLASS) otmp->spe = 1; + + if (spesgn == 0) { + spe = otmp->spe; + } else if (wizard) { + ; /* no alteration to spe */ + } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS || + is_weptool(otmp) || + (oclass==RING_CLASS && objects[typ].oc_charged)) { + if(spe > rnd(5) && spe > otmp->spe) spe = 0; + if(spe > 2 && Luck < 0) spesgn = -1; + } else { + if (oclass == WAND_CLASS) { + if (spe > 1 && spesgn == -1) spe = 1; + } else { + if (spe > 0 && spesgn == -1) spe = 0; + } + if (spe > otmp->spe) spe = otmp->spe; + } + + if (spesgn == -1) spe = -spe; + + /* set otmp->spe. This may, or may not, use spe... */ + switch (typ) { + case TIN: if (contents==EMPTY) { + otmp->corpsenm = NON_PM; + otmp->spe = 0; + } else if (contents==SPINACH) { + otmp->corpsenm = NON_PM; + otmp->spe = 1; + } + break; + case SLIME_MOLD: otmp->spe = ftype; + /* Fall through */ + case SKELETON_KEY: case CHEST: case LARGE_BOX: + case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE: + /* otmp->cobj already done in mksobj() */ + break; #ifdef MAIL - case SCR_MAIL: otmp->spe = 1; break; + case SCR_MAIL: otmp->spe = 1; break; #endif - case WAN_WISHING: - if (!wizard) { - otmp->spe = (rn2(10) ? -1 : 0); - break; - } - /* fall through, if wizard */ - default: otmp->spe = spe; - } - - /* set otmp->corpsenm or dragon scale [mail] */ - if (mntmp >= LOW_PM) { - if (mntmp == PM_LONG_WORM_TAIL) mntmp = PM_LONG_WORM; - - switch (typ) { - case TIN: - otmp->spe = 0; /* No spinach */ - if (dead_species(mntmp, FALSE)) { - otmp->corpsenm = NON_PM; /* it's empty */ - } else if (!(mons[mntmp].geno & G_UNIQ) && - !(mvitals[mntmp].mvflags & G_NOCORPSE) && - mons[mntmp].cnutrit != 0) { - otmp->corpsenm = mntmp; - } - break; - case CORPSE: - if (!(mons[mntmp].geno & G_UNIQ) && - !(mvitals[mntmp].mvflags & G_NOCORPSE)) { - if (mons[mntmp].msound == MS_GUARDIAN) - mntmp = genus(mntmp,1); - set_corpsenm(otmp, mntmp); - } - break; - case FIGURINE: - if (!(mons[mntmp].geno & G_UNIQ) - && !is_human(&mons[mntmp]) + case WAN_WISHING: + if (!wizard) { + otmp->spe = (rn2(10) ? -1 : 0); + break; + } + /* fall through, if wizard */ + default: otmp->spe = spe; + } + + /* set otmp->corpsenm or dragon scale [mail] */ + if (mntmp >= LOW_PM) { + if (mntmp == PM_LONG_WORM_TAIL) mntmp = PM_LONG_WORM; + + switch (typ) { + case TIN: + otmp->spe = 0; /* No spinach */ + if (dead_species(mntmp, FALSE)) { + otmp->corpsenm = NON_PM; /* it's empty */ + } else if (!(mons[mntmp].geno & G_UNIQ) && + !(mvitals[mntmp].mvflags & G_NOCORPSE) && + mons[mntmp].cnutrit != 0) { + otmp->corpsenm = mntmp; + } + break; + case CORPSE: + if (!(mons[mntmp].geno & G_UNIQ) && + !(mvitals[mntmp].mvflags & G_NOCORPSE)) { + if (mons[mntmp].msound == MS_GUARDIAN) + mntmp = genus(mntmp,1); + set_corpsenm(otmp, mntmp); + } + break; + case FIGURINE: + if (!(mons[mntmp].geno & G_UNIQ) + && !is_human(&mons[mntmp]) #ifdef MAIL - && mntmp != PM_MAIL_DAEMON + && mntmp != PM_MAIL_DAEMON #endif - ) - otmp->corpsenm = mntmp; - break; - case EGG: - mntmp = can_be_hatched(mntmp); - /* this also sets hatch timer if appropriate */ - set_corpsenm(otmp, mntmp); - break; - case STATUE: otmp->corpsenm = mntmp; - if (Has_contents(otmp) && verysmall(&mons[mntmp])) - delete_contents(otmp); /* no spellbook */ - otmp->spe = ishistoric ? STATUE_HISTORIC : 0; - break; - case SCALE_MAIL: - /* Dragon mail - depends on the order of objects */ - /* & dragons. */ - if (mntmp >= PM_GRAY_DRAGON && - mntmp <= PM_YELLOW_DRAGON) - otmp->otyp = GRAY_DRAGON_SCALE_MAIL + - mntmp - PM_GRAY_DRAGON; - break; - } - } - - /* set blessed/cursed -- setting the fields directly is safe - * since weight() is called below and addinv() will take care - * of luck */ - if (iscursed) { - curse(otmp); - } else if (uncursed) { - otmp->blessed = 0; - otmp->cursed = (Luck < 0 && !wizard); - } else if (blessed) { - otmp->blessed = (Luck >= 0 || wizard); - otmp->cursed = (Luck < 0 && !wizard); - } else if (spesgn < 0) { - curse(otmp); - } - - /* set eroded */ - if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) { - if (eroded && (is_flammable(otmp) || is_rustprone(otmp))) - otmp->oeroded = eroded; - if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp))) - otmp->oeroded2 = eroded2; - - /* set erodeproof */ - if (erodeproof && !eroded && !eroded2) - otmp->oerodeproof = (Luck >= 0 || wizard); - } - - /* set otmp->recharged */ - if (oclass == WAND_CLASS) { - /* prevent wishing abuse */ - if (otmp->otyp == WAN_WISHING && !wizard) rechrg = 1; - otmp->recharged = (unsigned)rechrg; - } - - /* set poisoned */ - if (ispoisoned) { - if (is_poisonable(otmp)) - otmp->opoisoned = (Luck >= 0); - else if (oclass == FOOD_CLASS) - /* try to taint by making it as old as possible */ - otmp->age = 1L; - } - /* and [un]trapped */ - if (trapped) { - if (Is_box(otmp) || typ == TIN) - otmp->otrapped = (trapped == 1); - } - - if (isgreased) otmp->greased = 1; - - if (isdiluted && otmp->oclass == POTION_CLASS && - otmp->otyp != POT_WATER) - otmp->odiluted = 1; - - /* set tin variety */ - if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard)) - set_tin_variety(otmp, tvariety); - - if (name) { - const char *aname; - short objtyp; - - /* an artifact name might need capitalization fixing */ - aname = artifact_name(name, &objtyp); - if (aname && objtyp == otmp->otyp) name = aname; - - otmp = oname(otmp, name); - if (otmp->oartifact) { - otmp->quan = 1L; - u.uconduct.wisharti++; /* KMH, conduct */ - } - } - - /* more wishing abuse: don't allow wishing for certain artifacts */ - /* and make them pay; charge them for the wish anyway! */ - if ((is_quest_artifact(otmp) || - (otmp->oartifact && rn2(nartifact_exist()) > 1)) && - !wizard) { - artifact_exists(otmp, safe_oname(otmp), FALSE); - obfree(otmp, (struct obj *) 0); - otmp = &zeroobj; - pline("For a moment, you feel %s in your %s, but it disappears!", - something, - makeplural(body_part(HAND))); - } - - if (halfeaten && otmp->oclass == FOOD_CLASS) { - if (otmp->otyp == CORPSE) - otmp->oeaten = mons[otmp->corpsenm].cnutrit; - else otmp->oeaten = objects[otmp->otyp].oc_nutrition; - /* (do this adjustment before setting up object's weight) */ - consume_oeaten(otmp, 1); - } - otmp->owt = weight(otmp); - if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160; - - return(otmp); + ) + otmp->corpsenm = mntmp; + break; + case EGG: + mntmp = can_be_hatched(mntmp); + /* this also sets hatch timer if appropriate */ + set_corpsenm(otmp, mntmp); + break; + case STATUE: otmp->corpsenm = mntmp; + if (Has_contents(otmp) && verysmall(&mons[mntmp])) + delete_contents(otmp); /* no spellbook */ + otmp->spe = ishistoric ? STATUE_HISTORIC : 0; + break; + case SCALE_MAIL: + /* Dragon mail - depends on the order of objects */ + /* & dragons. */ + if (mntmp >= PM_GRAY_DRAGON && + mntmp <= PM_YELLOW_DRAGON) + otmp->otyp = GRAY_DRAGON_SCALE_MAIL + + mntmp - PM_GRAY_DRAGON; + break; + } + } + + /* set blessed/cursed -- setting the fields directly is safe + * since weight() is called below and addinv() will take care + * of luck */ + if (iscursed) { + curse(otmp); + } else if (uncursed) { + otmp->blessed = 0; + otmp->cursed = (Luck < 0 && !wizard); + } else if (blessed) { + otmp->blessed = (Luck >= 0 || wizard); + otmp->cursed = (Luck < 0 && !wizard); + } else if (spesgn < 0) { + curse(otmp); + } + + /* set eroded */ + if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) { + if (eroded && (is_flammable(otmp) || is_rustprone(otmp))) + otmp->oeroded = eroded; + if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp))) + otmp->oeroded2 = eroded2; + + /* set erodeproof */ + if (erodeproof && !eroded && !eroded2) + otmp->oerodeproof = (Luck >= 0 || wizard); + } + + /* set otmp->recharged */ + if (oclass == WAND_CLASS) { + /* prevent wishing abuse */ + if (otmp->otyp == WAN_WISHING && !wizard) rechrg = 1; + otmp->recharged = (unsigned)rechrg; + } + + /* set poisoned */ + if (ispoisoned) { + if (is_poisonable(otmp)) + otmp->opoisoned = (Luck >= 0); + else if (oclass == FOOD_CLASS) + /* try to taint by making it as old as possible */ + otmp->age = 1L; + } + /* and [un]trapped */ + if (trapped) { + if (Is_box(otmp) || typ == TIN) + otmp->otrapped = (trapped == 1); + } + + if (isgreased) otmp->greased = 1; + + if (isdiluted && otmp->oclass == POTION_CLASS && + otmp->otyp != POT_WATER) + otmp->odiluted = 1; + + /* set tin variety */ + if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard)) + set_tin_variety(otmp, tvariety); + + if (name) { + const char *aname; + short objtyp; + + /* an artifact name might need capitalization fixing */ + aname = artifact_name(name, &objtyp); + if (aname && objtyp == otmp->otyp) name = aname; + + otmp = oname(otmp, name); + if (otmp->oartifact) { + otmp->quan = 1L; + u.uconduct.wisharti++; /* KMH, conduct */ + } + } + + /* more wishing abuse: don't allow wishing for certain artifacts */ + /* and make them pay; charge them for the wish anyway! */ + if ((is_quest_artifact(otmp) || + (otmp->oartifact && rn2(nartifact_exist()) > 1)) && + !wizard) { + artifact_exists(otmp, safe_oname(otmp), FALSE); + obfree(otmp, (struct obj *) 0); + otmp = &zeroobj; + pline("For a moment, you feel %s in your %s, but it disappears!", + something, + makeplural(body_part(HAND))); + } + + if (halfeaten && otmp->oclass == FOOD_CLASS) { + if (otmp->otyp == CORPSE) + otmp->oeaten = mons[otmp->corpsenm].cnutrit; + else otmp->oeaten = objects[otmp->otyp].oc_nutrition; + /* (do this adjustment before setting up object's weight) */ + consume_oeaten(otmp, 1); + } + otmp->owt = weight(otmp); + if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160; + + return(otmp); } int rnd_class(first,last) int first,last; { - int i, x, sum=0; - - if (first == last) - return (first); - for(i=first; i<=last; i++) - sum += objects[i].oc_prob; - if (!sum) /* all zero */ - return first + rn2(last-first+1); - x = rnd(sum); - for(i=first; i<=last; i++) - if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0) - return i; - return 0; + int i, x, sum=0; + + if (first == last) + return (first); + for(i=first; i<=last; i++) + sum += objects[i].oc_prob; + if (!sum) /* all zero */ + return first + rn2(last-first+1); + x = rnd(sum); + for(i=first; i<=last; i++) + if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0) + return i; + return 0; } STATIC_OVL const char * Japanese_item_name(i) int i; { - struct Jitem *j = Japanese_items; - - while(j->item) { - if (i == j->item) - return j->name; - j++; - } - return (const char *)0; + struct Jitem *j = Japanese_items; + + while(j->item) { + if (i == j->item) + return j->name; + j++; + } + return (const char *)0; } const char * suit_simple_name(suit) struct obj *suit; { - const char *suitnm, *esuitp; - - if (Is_dragon_mail(suit)) - return "dragon mail"; /* dragon scale mail */ - else if (Is_dragon_scales(suit)) - return "dragon scales"; - suitnm = OBJ_NAME(objects[suit->otyp]); - esuitp = eos((char *)suitnm); - if (strlen(suitnm) > 5 && !strcmp(esuitp - 5, " mail")) - return "mail"; /* most suits fall into this category */ - else if (strlen(suitnm) > 7 && !strcmp(esuitp - 7, " jacket")) - return "jacket"; /* leather jacket */ - /* suit is lame but armor is ambiguous and body armor is absurd */ - return "suit"; + const char *suitnm, *esuitp; + + if (Is_dragon_mail(suit)) + return "dragon mail"; /* dragon scale mail */ + else if (Is_dragon_scales(suit)) + return "dragon scales"; + suitnm = OBJ_NAME(objects[suit->otyp]); + esuitp = eos((char *)suitnm); + if (strlen(suitnm) > 5 && !strcmp(esuitp - 5, " mail")) + return "mail"; /* most suits fall into this category */ + else if (strlen(suitnm) > 7 && !strcmp(esuitp - 7, " jacket")) + return "jacket"; /* leather jacket */ + /* suit is lame but armor is ambiguous and body armor is absurd */ + return "suit"; } const char * @@ -3273,17 +3276,17 @@ cloak_simple_name(cloak) struct obj *cloak; { if (cloak) { - switch (cloak->otyp) { - case ROBE: - return "robe"; - case MUMMY_WRAPPING: - return "wrapping"; - case ALCHEMY_SMOCK: - return (objects[cloak->otyp].oc_name_known && - cloak->dknown) ? "smock" : "apron"; - default: - break; - } + switch (cloak->otyp) { + case ROBE: + return "robe"; + case MUMMY_WRAPPING: + return "wrapping"; + case ALCHEMY_SMOCK: + return (objects[cloak->otyp].oc_name_known && + cloak->dknown) ? "smock" : "apron"; + default: + break; + } } return "cloak"; } @@ -3312,12 +3315,12 @@ const char * mimic_obj_name(mtmp) struct monst *mtmp; { - if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) { - int idx = objects[mtmp->mappearance].oc_descr_idx; - if (mtmp->mappearance == GOLD_PIECE) return "gold"; - return obj_descr[idx].oc_name; - } - return "whatcha-may-callit"; + if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) { + int idx = objects[mtmp->mappearance].oc_descr_idx; + if (mtmp->mappearance == GOLD_PIECE) return "gold"; + return obj_descr[idx].oc_name; + } + return "whatcha-may-callit"; } /* @@ -3337,9 +3340,9 @@ const char *lastR; char *bufp, *endp; /* convert size_t (or int for ancient systems) to ordinary unsigned */ unsigned len, lenlimit, - len_qpfx = (unsigned)(qprefix ? strlen(qprefix) : 0), - len_qsfx = (unsigned)(qsuffix ? strlen(qsuffix) : 0), - len_lastR = (unsigned)strlen(lastR); + len_qpfx = (unsigned)(qprefix ? strlen(qprefix) : 0), + len_qsfx = (unsigned)(qsuffix ? strlen(qsuffix) : 0), + len_lastR = (unsigned)strlen(lastR); lenlimit = QBUFSZ - 1; endp = qbuf + lenlimit; @@ -3347,54 +3350,54 @@ const char *lastR; the result of short_oname() to be shorter than the length of the last resort string, but we ignore that possibility here) */ if (len_qpfx > lenlimit) - impossible("safe_qbuf: prefix too long (%u characters).", - len_qpfx); + impossible("safe_qbuf: prefix too long (%u characters).", + len_qpfx); else if (len_qpfx + len_qsfx > lenlimit) - impossible("safe_qbuf: suffix too long (%u + %u characters).", - len_qpfx, len_qsfx); + impossible("safe_qbuf: suffix too long (%u + %u characters).", + len_qpfx, len_qsfx); else if (len_qpfx + len_lastR + len_qsfx > lenlimit) - impossible("safe_qbuf: filler too long (%u + %u + %u characters).", - len_qpfx, len_lastR, len_qsfx); + impossible("safe_qbuf: filler too long (%u + %u + %u characters).", + len_qpfx, len_lastR, len_qsfx); /* the output buffer might be the same as the prefix if caller has already partially filled it */ if (qbuf == qprefix) { - /* prefix is already in the buffer */ - *endp = '\0'; + /* prefix is already in the buffer */ + *endp = '\0'; } else if (qprefix) { - /* put prefix into the buffer */ - (void)strncpy(qbuf, qprefix, lenlimit); - *endp = '\0'; + /* put prefix into the buffer */ + (void)strncpy(qbuf, qprefix, lenlimit); + *endp = '\0'; } else { - /* no prefix; output buffer starts out empty */ - qbuf[0] = '\0'; + /* no prefix; output buffer starts out empty */ + qbuf[0] = '\0'; } len = (unsigned)strlen(qbuf); if (len + len_lastR + len_qsfx > lenlimit) { - /* too long; skip formatting, last resort output is truncated */ - if (len < lenlimit) { - (void)strncpy(&qbuf[len], lastR, lenlimit - len); - *endp = '\0'; - len = (unsigned)strlen(qbuf); - if (qsuffix && len < lenlimit) { - (void)strncpy(&qbuf[len], qsuffix, lenlimit - len); - *endp = '\0'; - /* len = (unsigned)strlen(qbuf); */ - } - } + /* too long; skip formatting, last resort output is truncated */ + if (len < lenlimit) { + (void)strncpy(&qbuf[len], lastR, lenlimit - len); + *endp = '\0'; + len = (unsigned)strlen(qbuf); + if (qsuffix && len < lenlimit) { + (void)strncpy(&qbuf[len], qsuffix, lenlimit - len); + *endp = '\0'; + /* len = (unsigned)strlen(qbuf); */ + } + } } else { - /* suffix and last resort are guaranteed to fit */ - len += len_qsfx; /* include the pending suffix */ - /* format the object */ - bufp = short_oname(obj, func, altfunc, lenlimit - len); - if (len + strlen(bufp) <= lenlimit) - Strcat(qbuf, bufp); /* formatted name fits */ - else - Strcat(qbuf, lastR); /* use last resort */ - releaseobuf(bufp); - - if (qsuffix) Strcat(qbuf, qsuffix); + /* suffix and last resort are guaranteed to fit */ + len += len_qsfx; /* include the pending suffix */ + /* format the object */ + bufp = short_oname(obj, func, altfunc, lenlimit - len); + if (len + strlen(bufp) <= lenlimit) + Strcat(qbuf, bufp); /* formatted name fits */ + else + Strcat(qbuf, lastR); /* use last resort */ + releaseobuf(bufp); + + if (qsuffix) Strcat(qbuf, qsuffix); } /* assert( strlen(qbuf) < QBUFSZ ); */ return qbuf; diff --git a/src/read.c b/src/read.c index 9be9f9390..22702169a 100644 --- a/src/read.c +++ b/src/read.c @@ -2031,7 +2031,7 @@ create_particular() { char buf[BUFSZ], *bufp, monclass; int which, tryct, i, firstchoice = NON_PM; - struct permonst *whichpm; + struct permonst *whichpm = NULL; struct monst *mtmp; boolean madeany = FALSE; boolean maketame, makepeaceful, makehostile;