Merge branch 'master' into win32-x64-working

Conflicts:
	src/files.c
	src/potion.c
	sys/winnt/Makefile.msc

 Changes to be committed:
	modified:   .gitignore
	modified:   DEVEL/hooksdir/nhsub
	modified:   dat/.gitignore
	modified:   dat/opthelp
	modified:   doc/Guidebook.mn
	modified:   doc/Guidebook.tex
	modified:   doc/fixes35.0
	modified:   include/context.h
	modified:   include/decl.h
	modified:   include/extern.h
	modified:   include/flag.h
	modified:   include/hack.h
	modified:   include/patchlevel.h
	modified:   src/apply.c
	modified:   src/attrib.c
	modified:   src/decl.c
	modified:   src/do.c
	modified:   src/do_name.c
	modified:   src/dothrow.c
	modified:   src/eat.c
	modified:   src/files.c
	modified:   src/hack.c
	modified:   src/invent.c
	modified:   src/lock.c
	modified:   src/mklev.c
	modified:   src/mondata.c
	modified:   src/monmove.c
	modified:   src/music.c
	modified:   src/options.c
	modified:   src/potion.c
	modified:   src/pray.c
	modified:   src/sit.c
	modified:   src/sp_lev.c
	modified:   src/uhitm.c
	modified:   sys/share/posixregex.c
	modified:   sys/winnt/Makefile.msc
	modified:   util/.gitignore
	modified:   win/win32/vs2010/NetHackW.vcxproj
This commit is contained in:
nhmall
2015-04-14 18:23:48 -04:00
38 changed files with 272 additions and 139 deletions

View File

@@ -703,6 +703,14 @@ register xchar x, y;
}
}
const char *
beautiful()
{
return (ACURR(A_CHA) > 14) ?
(poly_gender() == 1 ? "beautiful" : "handsome") : "ugly";
}
#define WEAK 3 /* from eat.c */
static const char look_str[] = "look %s.";
@@ -720,8 +728,7 @@ struct obj *obj;
if(!getdir((char *)0)) return 0;
invis_mirror = Invis;
useeit = !Blind && (!invis_mirror || See_invisible);
uvisage = (ACURR(A_CHA) > 14) ?
(poly_gender() == 1 ? "beautiful" : "handsome") : "ugly";
uvisage = beautiful();
mirror = simpleonames(obj); /* "mirror" or "looking glass" */
if(obj->cursed && !rn2(2)) {
if (!Blind)

View File

@@ -371,15 +371,6 @@ boolean inc_or_dec;
if (moves > 0 && (i == A_STR || i == A_CON)) (void)encumber_msg();
}
/* hunger values - from eat.c */
#define SATIATED 0
#define NOT_HUNGRY 1
#define HUNGRY 2
#define WEAK 3
#define FAINTING 4
#define FAINTED 5
#define STARVED 6
STATIC_OVL void
exerper()
{

View File

@@ -216,7 +216,7 @@ NEARDATA struct c_color_names c_color_names = {
"black", "amber", "golden",
"light blue", "red", "green",
"silver", "blue", "purple",
"white"
"white", "orange"
};
struct menucoloring *menu_colorings = NULL;

View File

@@ -8,6 +8,8 @@
#include "lev.h"
STATIC_DCL void FDECL(trycall, (struct obj *));
STATIC_DCL void NDECL(polymorph_sink);
STATIC_DCL boolean NDECL(teleport_sink);
STATIC_DCL void FDECL(dosinkring, (struct obj *));
STATIC_PTR int FDECL(drop, (struct obj *));
@@ -259,6 +261,72 @@ register struct obj *obj;
docall(obj);
}
/** Transforms the sink at the player's position into
* a fountain, throne, altar or grave. */
STATIC_DCL
void
polymorph_sink()
{
if (levl[u.ux][u.uy].typ != SINK) return;
level.flags.nsinks--;
levl[u.ux][u.uy].doormask = 0;
switch(rn2(4)) {
default:
case 0:
levl[u.ux][u.uy].typ = FOUNTAIN;
level.flags.nfountains++;
break;
case 1:
levl[u.ux][u.uy].typ = THRONE;
break;
case 2:
levl[u.ux][u.uy].typ = ALTAR;
levl[u.ux][u.uy].altarmask = Align2amask(rn2((int)A_LAWFUL+2) - 1);
break;
case 3:
levl[u.ux][u.uy].typ = ROOM;
make_grave(u.ux, u.uy, (char *) 0);
break;
}
pline_The("sink transforms into %s!",
(levl[u.ux][u.uy].typ == THRONE) ?
"a throne" : an(surface(u.ux, u.uy)));
newsym(u.ux,u.uy);
}
/** Teleports the sink at the player's position.
* @return TRUE if sink teleported */
STATIC_DCL
boolean
teleport_sink()
{
int cx, cy;
int cnt = 0;
struct trap *trp;
struct engr *eng;
do {
cx = rnd(COLNO-1);
cy = rn2(ROWNO);
trp = t_at(cx,cy);
eng = engr_at(cx,cy);
} while (((levl[cx][cy].typ != ROOM) || (trp) || (eng) ||
cansee(cx,cy)) && (cnt++ < 200));
if ((levl[cx][cy].typ == ROOM) && !trp && !eng) {
/* create sink at new position */
levl[cx][cy].typ = SINK;
levl[cx][cy].looted = levl[u.ux][u.uy].looted;
newsym(cx,cy);
/* remove old sink */
levl[u.ux][u.uy].typ = ROOM;
levl[u.ux][u.uy].looted = 0;
newsym(u.ux,u.uy);
return TRUE;
}
return FALSE;
}
STATIC_OVL
void
dosinkring(obj) /* obj is a ring being dropped over a kitchen sink */
@@ -266,6 +334,7 @@ register struct obj *obj;
{
register struct obj *otmp,*otmp2;
register boolean ideed = TRUE;
boolean nosink = FALSE;
You("drop %s down the drain.", doname(obj));
obj->in_use = TRUE; /* block free identification via interrupt */
@@ -288,8 +357,9 @@ giveback:
You("smell rotten %s.", makeplural(fruitname(FALSE)));
break;
case RIN_AGGRAVATE_MONSTER:
pline("Several flies buzz angrily around the sink.");
break;
pline("Several %s buzz angrily around the sink.",
Hallucination ? makeplural(rndmonnam(NULL)) : "flies");
break;
case RIN_SHOCK_RESISTANCE:
pline("Static electricity surrounds the sink.");
break;
@@ -354,7 +424,8 @@ giveback:
You_see("the ring slide right down the drain!");
break;
case RIN_SEE_INVISIBLE:
You_see("some air in the sink.");
You_see("some %s in the sink.",
Hallucination ? "oxygen molecules" : "air");
break;
case RIN_STEALTH:
pline_The("sink seems to blend into the floor for a moment.");
@@ -376,13 +447,15 @@ giveback:
pline_The("sink glows %s for a moment.", hcolor(NH_WHITE));
break;
case RIN_TELEPORTATION:
pline_The("sink momentarily vanishes.");
nosink = teleport_sink();
pline_The("sink %svanishes.", nosink ? "" : "momentarily ");
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.");
polymorph_sink();
nosink = TRUE;
break;
case RIN_POLYMORPH_CONTROL:
pline_The("sink momentarily looks like a regularly erupting geyser.");
@@ -391,9 +464,9 @@ giveback:
}
if(ideed)
trycall(obj);
else
else if (!nosink)
You_hear("the ring bouncing down the drainpipe.");
if (!rn2(20)) {
if (!rn2(20) && !nosink) {
pline_The("sink backs up, leaving %s.", doname(obj));
obj->in_use = FALSE;
dropx(obj);

View File

@@ -420,10 +420,7 @@ do_mname()
mtmp = u.usteed;
else {
pline("This %s creature is called %s and cannot be renamed.",
ACURR(A_CHA) > 14 ?
(flags.female ? "beautiful" : "handsome") :
"ugly",
plname);
beautiful(), plname);
return;
}
} else

View File

@@ -1665,6 +1665,21 @@ xchar x, y; /* object location (ox, oy may not be right) */
return 1;
}
void
release_camera_demon(obj, x,y)
struct obj *obj;
xchar x,y;
{
struct monst *mtmp;
if (!rn2(3) && (mtmp = makemon(&mons[rn2(3) ? PM_HOMUNCULUS : PM_IMP],x,y, NO_MM_FLAGS)) != 0) {
if (canspotmon(mtmp))
pline("%s is released!", Hallucination ?
An(rndmonnam(NULL)) : "The picture-painting demon");
mtmp->mpeaceful = !obj->cursed;
set_malign(mtmp);
}
}
/*
* Unconditionally break an object. Assumes all resistance checks
* and break messages have been delivered prior to getting here.
@@ -1707,6 +1722,9 @@ boolean from_invent;
}
/* monster breathing isn't handled... [yet?] */
break;
case EXPENSIVE_CAMERA:
release_camera_demon(obj, x,y);
break;
case EGG:
/* breaking your own eggs is bad luck */
if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM)

View File

@@ -39,15 +39,6 @@ STATIC_DCL boolean FDECL(maybe_cannibal, (int,BOOLEAN_P));
char msgbuf[BUFSZ];
/* hunger texts used on bottom line (each 8 chars long) */
#define SATIATED 0
#define NOT_HUNGRY 1
#define HUNGRY 2
#define WEAK 3
#define FAINTING 4
#define FAINTED 5
#define STARVED 6
/* also used to see if you're allowed to eat cats and dogs */
#define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
@@ -75,6 +66,7 @@ STATIC_OVL NEARDATA const char allobj[] = {
STATIC_OVL boolean force_save_hs = FALSE;
/* see hunger states in hack.h - texts used on bottom line */
const char *hu_stat[] = {
"Satiated",
" ",

View File

@@ -1,4 +1,4 @@
/* NetHack 3.5 files.c $NHDT-Date: 1427337311 2015/03/26 02:35:11 $ $NHDT-Branch: derek-farming $:$NHDT-Revision: 1.141 $ */
/* NetHack 3.5 files.c $NHDT-Date: 1428972596 2015/04/14 00:49:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.164 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -3346,10 +3346,8 @@ int tribpassage;
char *endp;
char line[BUFSZ];
int scopes[4] = {0, SECTIONSCOPE, TITLESCOPE, PASSAGESCOPE};
int scope = 0, section = 0, passage = 0, book = 0;
int linect = 0, passagecnt = 0, targetpassage = 0, textcnt = 0;
char *sectionnm = "", *booknm = "";
int scope = 0;
int linect = 0, passagecnt = 0, targetpassage = 0;
const char *badtranslation = "an incomprehensible foreign translation";
boolean matchedsection = FALSE, matchedtitle = FALSE;
winid tribwin = WIN_ERR;

View File

@@ -347,7 +347,7 @@ still_chewing(x,y)
if (!boulder && IS_ROCK(lev->typ) && !may_dig(x,y)) {
You("hurt your teeth on the %s.",
IS_TREE(lev->typ) ? "tree" : "hard stone");
lev->typ == IRONBARS ? "bars" : (IS_TREE(lev->typ) ? "tree" : "hard stone"));
nomul(0);
return 1;
} else if (context.digging.pos.x != x || context.digging.pos.y != y ||
@@ -362,9 +362,10 @@ still_chewing(x,y)
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 || IS_TREE(lev->typ) || lev->typ == IRONBARS) ? "on a" : "a hole in the",
boulder ? "boulder" :
IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door");
IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" :
lev->typ == IRONBARS ? "bar" : "door");
watch_dig((struct monst *)0, x, y, FALSE);
return 1;
} else if ((context.digging.effort += (30 + u.udaminc)) <= 100) {
@@ -373,7 +374,8 @@ still_chewing(x,y)
context.digging.chew ? "continue" : "begin",
boulder ? "boulder" :
IS_TREE(lev->typ) ? "tree" :
IS_ROCK(lev->typ) ? "rock" : "door");
IS_ROCK(lev->typ) ? "rock" :
lev->typ == IRONBARS ? "bars" : "door");
context.digging.chew = TRUE;
watch_dig((struct monst *)0, x, y, FALSE);
return 1;
@@ -418,6 +420,9 @@ still_chewing(x,y)
} else if (IS_TREE(lev->typ)) {
digtxt = "chew through the tree.";
lev->typ = ROOM;
} else if (lev->typ == IRONBARS) {
digtxt = "eat through the bars.";
dissolve_bars(x,y);
} else if (lev->typ == SDOOR) {
if (lev->doormask & D_TRAPPED) {
lev->doormask = D_NODOOR;
@@ -622,6 +627,7 @@ int mode;
register struct rm *tmpr = &levl[x][y];
register struct rm *ust;
context.door_opened = FALSE;
/*
* Check for physical obstacles. First, the place we are going.
*/
@@ -630,10 +636,15 @@ int mode;
if (Passes_walls && may_passwall(x,y)) {
; /* do nothing */
} else if (tmpr->typ == IRONBARS) {
if ((dmgtype(youmonst.data, AD_RUST) ||
dmgtype(youmonst.data, AD_CORR)) &&
mode == DO_MOVE && still_chewing(x,y)) {
return FALSE;
}
if (!(Passes_walls || passes_bars(youmonst.data))) {
if (iflags.mention_walls)
You("cannot pass through the bars.");
return FALSE;
return FALSE;
}
} else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
/* Eat the rock. */
@@ -670,8 +681,10 @@ int mode;
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 (flags.autoopen && !context.run && !Confusion && !Stunned && !Fumbling) {
context.door_opened = context.move = doopen_indir(x, y);
} 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));
@@ -1395,9 +1408,11 @@ domove()
}
if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
context.move = 0;
nomul(0);
return;
if (!context.door_opened) {
context.move = 0;
nomul(0);
}
return;
}
/* Move ball and chain. */

View File

@@ -2540,6 +2540,7 @@ mergable(otmp, obj) /* returns TRUE if obj & otmp can be merged */
register struct obj *otmp, *obj;
{
int objnamelth = 0, otmpnamelth = 0;
if (obj == otmp) return FALSE; /* already the same object */
if (obj->otyp != otmp->otyp) return FALSE;
/* coins of the same kind will always merge */
if (obj->oclass == COIN_CLASS) return TRUE;

View File

@@ -523,6 +523,14 @@ doforce() /* try to force a chest with your weapon */
int
doopen() /* try to open a door */
{
return doopen_indir(0, 0);
}
int
doopen_indir(x, y) /* try to open a door in direction u.dx/u.dy */
int x, y;
{
coord cc;
register struct rm *door;
struct monst *mtmp;
@@ -539,7 +547,10 @@ doopen() /* try to open a door */
return 0;
}
if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return(0);
if (x > 0 && y > 0) {
cc.x = x;
cc.y = y;
} else if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return(0);
if((cc.x == u.ux) && (cc.y == u.uy)) return(0);

View File

@@ -492,6 +492,15 @@ int trap_type;
if(rn2(7))
dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
else {
/* inaccessible niches occasionally have iron bars */
if (!rn2(5) && IS_WALL(levl[xx][yy].typ)) {
levl[xx][yy].typ = IRONBARS;
if (rn2(3))
(void) mkcorpstat(CORPSE,
(struct monst *)0,
mkclass(S_HUMAN, 0),
xx, yy+dy, TRUE);
}
if (!level.flags.noteleport)
(void) mksobj_at(SCR_TELEPORTATION,
xx, yy+dy, TRUE, FALSE);

View File

@@ -285,6 +285,7 @@ struct permonst *mptr;
{
return (boolean) (passes_walls(mptr) || amorphous(mptr) ||
unsolid(mptr) || is_whirly(mptr) || verysmall(mptr) ||
dmgtype(mptr, AD_CORR) || dmgtype(mptr, AD_RUST) ||
(slithy(mptr) && !bigmonst(mptr)));
}

View File

@@ -1180,7 +1180,14 @@ postmov:
add_damage(mtmp->mx, mtmp->my, 0L);
}
} else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) {
if (flags.verbose && canseemon(mtmp))
if (may_dig(mtmp->mx,mtmp->my) &&
(dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR))) {
if (canseemon(mtmp))
pline("%s eats through the iron bars.",
Monnam(mtmp));
dissolve_bars(mtmp->mx, mtmp->my);
return(3);
} else if (flags.verbose && canseemon(mtmp))
Norep("%s %s %s the iron bars.", Monnam(mtmp),
/* pluralization fakes verb conjugation */
makeplural(locomotion(ptr, "pass")),
@@ -1266,6 +1273,14 @@ postmov:
return(mmoved);
}
void
dissolve_bars(x, y)
register int x, y;
{
levl[x][y].typ = (Is_special(&u.uz) || *in_rooms(x,y,0)) ? ROOM : CORR;
newsym(x, y);
}
boolean
closed_door(x, y)
register int x, y;

View File

@@ -453,7 +453,7 @@ struct obj *instr;
if (do_spec && instr->spe > 0) {
consume_obj_charge(instr, TRUE);
You("produce soft music.");
You("produce %s music.", Hallucination ? "piped" : "soft");
put_monsters_to_sleep(u.ulevel * 5);
exercise(A_DEX, TRUE);
break;

View File

@@ -77,6 +77,7 @@ static struct Bool_Opt
{"asksavedisk", (boolean *)0, FALSE, SET_IN_FILE},
#endif
{"autodig", &flags.autodig, FALSE, SET_IN_GAME},
{"autoopen", &flags.autoopen, TRUE, SET_IN_GAME},
{"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
{"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
#if defined(MICRO) && !defined(AMIGA)

View File

@@ -1,4 +1,4 @@
/* NetHack 3.5 potion.c $NHDT-Date: 1426953330 2015/03/21 15:55:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.99 $ */
/* NetHack 3.5 potion.c $NHDT-Date: 1428972597 2015/04/14 00:49:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.111 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1818,6 +1818,15 @@ dodip()
return 1;
}
if(potion->otyp == POT_ACID && obj->otyp == CORPSE &&
obj->corpsenm == PM_LICHEN && !Blind) {
pline("%s %s %s around the edges.", The(cxname(obj)),
otense(obj, "turn"), potion->odiluted ?
hcolor(NH_ORANGE) : hcolor(NH_RED));
potion->in_use = FALSE; /* didn't go poof */
return(1);
}
if(is_poisonable(obj)) {
if(potion->otyp == POT_SICKNESS && !obj->opoisoned) {
char buf[BUFSZ];

View File

@@ -148,16 +148,6 @@ in_trouble()
struct obj *otmp;
int i, j, count=0;
/* Borrowed from eat.c */
#define SATIATED 0
#define NOT_HUNGRY 1
#define HUNGRY 2
#define WEAK 3
#define FAINTING 4
#define FAINTED 5
#define STARVED 6
/*
* major troubles
*/
@@ -1369,7 +1359,7 @@ dosacrifice()
a_gname(), u_gname());
pline("%s is enraged...", u_gname());
pline("Fortunately, %s permits you to live...", a_gname());
pline(cloud_of_smoke, hcolor("orange"));
pline(cloud_of_smoke, hcolor(NH_ORANGE));
done(ESCAPED);
} else { /* super big win */
adjalign(10);

View File

@@ -67,9 +67,14 @@ dosit()
register struct obj *obj;
obj = level.objects[u.ux][u.uy];
You("sit on %s.", the(xname(obj)));
if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH))
pline("It's not very comfortable...");
if (youmonst.data->mlet == S_DRAGON && obj->oclass == COIN_CLASS) {
You("coil up around your %shoard.",
(obj->quan + money_cnt(invent) < u.ulevel*1000) ? "meager " : "");
} else {
You("sit on %s.", the(xname(obj)));
if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH))
pline("It's not very comfortable...");
}
} else if (trap != 0 || (u.utrap && (u.utraptype >= TT_LAVA))) {
if (u.utrap) {
exercise(A_WIS, FALSE); /* you're getting stuck longer */

View File

@@ -407,7 +407,7 @@ opvar_clone(ov)
case SPOVAR_VARIABLE:
case SPOVAR_STRING:
case SPOVAR_SEL:
tmpov->vardata.str = strdup(ov->vardata.str);
tmpov->vardata.str = dupstr(ov->vardata.str);
break;
default: impossible("Unknown push value type (%i)!", ov->spovartyp);
}
@@ -2677,7 +2677,7 @@ spo_monster(coder)
case SP_M_V_NAME:
if ((OV_typ(parm) == SPOVAR_STRING) &&
!tmpmons.name.str)
tmpmons.name.str = strdup(OV_s(parm));
tmpmons.name.str = dupstr(OV_s(parm));
break;
case SP_M_V_APPEAR:
if ((OV_typ(parm) == SPOVAR_INT) &&
@@ -2685,7 +2685,7 @@ spo_monster(coder)
tmpmons.appear = OV_i(parm);
opvar_free(parm);
OV_pop(parm);
tmpmons.appear_as.str = strdup(OV_s(parm));
tmpmons.appear_as.str = dupstr(OV_s(parm));
}
break;
case SP_M_V_ASLEEP:
@@ -2820,7 +2820,7 @@ spo_object(coder)
case SP_O_V_NAME:
if ((OV_typ(parm) == SPOVAR_STRING) &&
!tmpobj.name.str)
tmpobj.name.str = strdup(OV_s(parm));
tmpobj.name.str = dupstr(OV_s(parm));
break;
case SP_O_V_CORPSENM:
if (OV_typ(parm) == SPOVAR_MONST) {
@@ -3925,7 +3925,7 @@ spo_levregion(coder)
tmplregion->del_islev = OV_i(del_islev);
tmplregion->rtype = OV_i(rtype);
tmplregion->padding = OV_i(padding);
tmplregion->rname.str = strdup(OV_s(rname));
tmplregion->rname.str = dupstr(OV_s(rname));
if(!tmplregion->in_islev) {
get_location(&tmplregion->inarea.x1, &tmplregion->inarea.y1,
@@ -4494,7 +4494,7 @@ spo_var_init(coder)
tmpvar = (struct splev_var *)malloc(sizeof(struct splev_var));
if (!tmpvar) panic("newvar tmpvar alloc");
tmpvar->next = coder->frame->variables;
tmpvar->name = strdup(OV_s(vname));
tmpvar->name = dupstr(OV_s(vname));
coder->frame->variables = tmpvar;
if (OV_i(arraylen) < 0) {

View File

@@ -741,6 +741,7 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
case EXPENSIVE_CAMERA:
You("succeed in destroying %s. Congratulations!",
ysimple_name(obj));
release_camera_demon(obj, u.ux, u.uy);
useup(obj);
return(TRUE);
/*NOTREACHED*/