1
0
Fork 0
mirror of https://codeberg.org/noisytoot/notnotdnethack.git synced 2024-11-21 16:55:06 +00:00
notnotdnethack/src/apply.c

9366 lines
261 KiB
C

/* SCCS Id: @(#)apply.c 3.4 2003/11/18 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include <math.h>
#include "hack.h"
#include "artifact.h"
#include "xhity.h"
static const char tools[] = { CHAIN_CLASS, SCOIN_CLASS, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 };
static const char tools_too[] = { ALL_CLASSES, SCOIN_CLASS, TOOL_CLASS, POTION_CLASS,
WEAPON_CLASS, WAND_CLASS, GEM_CLASS, CHAIN_CLASS, 0 };
static const char apply_armor[] = { ARMOR_CLASS, 0 };
static const char imperial_repairs[] = { AMULET_CLASS, ARMOR_CLASS, RING_CLASS, WAND_CLASS, 0 };
static const char apply_wand[] = { WAND_CLASS, 0 };
static const char apply_gem[] = { GEM_CLASS, 0 };
static const char chain_class[] = { CHAIN_CLASS, 0 };
static const char apply_all[] = { ALL_CLASSES, CHAIN_CLASS, 0 };
#define TREPH_THOUGHTS 1
#define TREPH_CRYSTALS 2
static int use_camera(struct obj *);
static int do_present_item(struct obj *);
static int use_towel(struct obj *);
static boolean its_dead(int,int,int *,struct obj*);
static int use_stethoscope(struct obj *);
static void use_whistle(struct obj *);
static void use_leash(struct obj *);
static int use_mirror(struct obj **);
static void use_candelabrum(struct obj *);
static void use_candle(struct obj **);
static void use_lamp(struct obj *);
static int swap_aegis(struct obj *);
static int aesculapius_poke(struct obj *);
static int ilmater_touch(struct obj *);
static int use_rakuyo(struct obj *);
static int use_mercy_blade(struct obj *);
static int use_force_blade(struct obj *);
static void light_cocktail(struct obj *);
static void light_torch(struct obj *);
static void use_trephination_kit(struct obj *);
static void use_tinning_kit(struct obj *);
static int use_figurine(struct obj **);
static int use_crystal_skull(struct obj **);
static void use_grease(struct obj *);
static void vape(struct obj *);
static void use_trap(struct obj *);
static void use_stone(struct obj *);
static int use_sensor(struct obj *);
static int sensorMenu(void);
static int use_hypospray(struct obj *);
static int use_droven_cloak(struct obj **);
static int use_darkweavers_cloak(struct obj *);
static int set_trap(void); /* occupation callback */
static int use_pole(struct obj *);
static int use_cream_pie(struct obj *);
static int use_grapple(struct obj *);
static int use_crook(struct obj *);
static int use_dilithium(struct obj *);
static int use_doll(struct obj *);
static int use_doll_tear(struct obj *);
static int use_pyramid(struct obj *);
static int use_vortex(struct obj *);
static int use_rift(struct obj *);
static int do_break_wand(struct obj *);
static int do_flip_coin(struct obj *);
static void soul_crush_consequence(struct obj *);
static int do_soul_coin(struct obj *);
static boolean figurine_location_checks(struct obj *, coord *, boolean);
static boolean uhave_graystone(void);
static int do_carve_obj(struct obj *);
static int pick_rune(boolean);
static void describe_rune(int);
static char pick_carvee(void);
static int res_engine_menu(struct obj *);
static int dotrephination_options(void);
static const char no_elbow_room[] = "don't have enough elbow-room to maneuver.";
static int
use_camera(struct obj *obj)
{
register struct monst *mtmp;
if(Underwater) {
pline("Using your camera underwater would void the warranty.");
return MOVE_CANCELLED;
}
if(!getdir((char *)0)) return MOVE_CANCELLED;
if (obj->spe <= 0) {
pline("%s", nothing_happens);
return MOVE_STANDARD;
}
consume_obj_charge(obj, TRUE);
if (obj->cursed && !rn2(2)) {
(void) zapyourself(obj, TRUE);
} else if (u.uswallow) {
You("take a picture of %s %s.", s_suffix(mon_nam(u.ustuck)),
mbodypart(u.ustuck, STOMACH));
} else if (u.dz) {
You("take a picture of the %s.",
(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
} else if (!u.dx && !u.dy) {
(void) zapyourself(obj, TRUE);
} else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT,
(int (*)(struct monst *,struct obj *))0,
(int (*)(struct obj *,struct obj *))0,
obj, NULL)) != 0) {
obj->ox = u.ux, obj->oy = u.uy;
(void) flash_hits_mon(mtmp, obj);
}
return MOVE_STANDARD;
}
static int
do_present_item(struct obj *obj)
{
register struct monst *mtmp, *tm;
const char *word = obj->oclass == RING_CLASS ? "ring" : obj->oclass == AMULET_CLASS ? "amulet" : "item";
if(!getdir((char *)0)) return MOVE_CANCELLED;
if(obj->oward == 0 && !(obj->ohaluengr)){
exercise(A_WIS, FALSE);
return MOVE_INSTANT;
}
if (u.uswallow) {
You("display the %s engraving to %s %s.", s_suffix(word), s_suffix(mon_nam(u.ustuck)),
mbodypart(u.ustuck, STOMACH));
pline("Nothing happens.");
exercise(A_WIS, FALSE);
return MOVE_INSTANT;
} else if (u.dz) {
You("display the %s engraving to the %s.", s_suffix(word),
(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
if(u.dz < 0 || obj->oartifact){
pline("Nothing happens.");
exercise(A_WIS, FALSE);
return MOVE_INSTANT;
}
if(is_lava(u.ux, u.uy) || flags.beginner || !(u.ualign.type == A_CHAOTIC || Hallucination) ){
pline("Nothing happens.");
if(u.ualign.type == A_LAWFUL) exercise(A_WIS, FALSE);
return MOVE_INSTANT;
}else{
You_feel("as though the engraving on the %s could fall right off!", word);
if(yn("Give it a push?") == 'n'){
pline("Nothing happens.");
return MOVE_INSTANT;
}
else{
struct engr *engrHere = engr_at(u.ux,u.uy);
if(u.ualign.type == A_LAWFUL) exercise(A_WIS, FALSE);
if (IS_ALTAR(levl[u.ux][u.uy].typ)) {
altar_wrath(u.ux, u.uy);
return MOVE_INSTANT;
}
if(!engrHere){
make_engr_at(u.ux, u.uy, "", (moves - multi), DUST); /* absense of text = dust */
engrHere = engr_at(u.ux,u.uy); /*note: make_engr_at does not return the engraving it made, it returns void instead*/
}
if(obj->ohaluengr == engrHere->halu_ward && obj->oward == engrHere->ward_id){
pline("the engraving tumbles off the %s to join it's fellows.", word);
engrHere->complete_wards += engrHere->halu_ward ? 0 : get_num_wards_added(engrHere->ward_id,engrHere->complete_wards);
obj->ohaluengr = FALSE;
obj->oward = FALSE;
}
else{
pline("the engraving tumbles off the %s%s.", word, engrHere->ward_id ? "and covers the existing drawing" : "");
engrHere->ward_id = obj->oward;
engrHere->halu_ward = obj->ohaluengr;
engrHere->complete_wards = engrHere->halu_ward ? 1 : get_num_wards_added(engrHere->ward_id,0);
engrHere->ward_type = obj->blessed ? BURN : obj->cursed ? DUST : ENGRAVE;
if( !(obj->ohaluengr) && !(u.wardsknown & get_wardID(engrHere->ward_id)) ){
You("have learned a new warding sign!");
u.wardsknown |= get_wardID(engrHere->ward_id);
}
obj->ohaluengr = FALSE;
obj->oward = FALSE;
}
}
}
} else if (!u.dx && !u.dy) {
if(!(obj->ohaluengr)){
pline("A %s is engraved on the %s.", wardDecode[obj->oward], word);
if( !(u.wardsknown & get_wardID(obj->oward)) ){
You("have learned a new warding sign!");
u.wardsknown |= get_wardID(obj->oward);
}
}
else{
pline("There is %s engraved on the %s.", fetchHaluWard((int)obj->oward), word);
}
return MOVE_STANDARD;
} else if (isok(u.ux+u.dx, u.uy+u.dy) && (mtmp = m_at(u.ux+u.dx, u.uy+u.dy)) != 0) {
You("display the %s engraving to %s.", s_suffix(word), mon_nam(mtmp));
if (obj->cursed && rn2(3)) {
pline("But the %s engraving is fogged over!", s_suffix(word));
return MOVE_STANDARD;
}
if(!(obj->ohaluengr) || obj->oward == CERULEAN_SIGN){
if(
(obj->oward == HEPTAGRAM && scaryHept(1, mtmp)) ||
(obj->oward == GORGONEION && scaryGorg(1, mtmp)) ||
(obj->oward == CIRCLE_OF_ACHERON && scaryCircle(1, mtmp)) ||
(obj->oward == PENTAGRAM && scaryPent(1, mtmp)) ||
(obj->oward == HEXAGRAM && scaryHex(1, mtmp)) ||
(obj->oward == HAMSA && scaryHam(1, mtmp)) ||
( (obj->oward == ELDER_SIGN || obj->oward == CERULEAN_SIGN) && scarySign(obj->oartifact == ART_STAR_OF_HYPERNOTUS ? 6 : 1, mtmp)) ||
(obj->oward == ELDER_ELEMENTAL_EYE && scaryEye(1, mtmp)) ||
(obj->oward == SIGN_OF_THE_SCION_QUEEN && scaryQueen(1, mtmp)) ||
(obj->oward == CARTOUCHE_OF_THE_CAT_LORD && scaryCat(1, mtmp)) ||
(obj->oward == WINGS_OF_GARUDA && scaryWings(1, mtmp)) ||
/* (obj->oward == SIGIL_OF_CTHUGHA && (1, mtmp)) ||
(obj->oward == BRAND_OF_ITHAQUA && (1, mtmp)) ||
(obj->oward == TRACERY_OF_KARAKAL && (1, mtmp)) || These wards curently don't have scaryX functions. */
(obj->oward == YELLOW_SIGN && scaryYellow(1, mtmp)) ||
(obj->oward == TOUSTEFNA && scaryTou(mtmp)) ||
(obj->oward == DREPRUN && scaryDre(mtmp)) ||
/* (obj->oward == OTTASTAFUR && (mtmp)) ||
(obj->oward == KAUPALOKI && (mtmp)) || Unimplemented runes. */
(obj->oward == VEIOISTAFUR && scaryVei(mtmp)) ||
(obj->oward == THJOFASTAFUR && scaryThj(mtmp))
){
if (rn2(7))
monflee(mtmp, rnd(10), TRUE, TRUE);
else
monflee(mtmp, rnd(100), TRUE, TRUE);
}
} else if(obj->ohaluengr && obj->oward >= FIRST_DROW_SYM && obj->oward <= LAST_DROW_SYM &&
(is_elf(mtmp->data) || is_drow(mtmp->data) || mtmp->mtyp == PM_EDDERKOP)
){
if(flags.stag &&
(mtmp->mfaction == u.start_house || allied_faction(mtmp->mfaction,u.start_house)) &&
obj->oward == EDDER_SYMBOL &&
!(mtmp->female)
){
verbalize("The revolution has begun!");
for(tm = fmon; tm; tm = tm->nmon){
if((is_drow(tm->data) && (obj->oward == tm->mfaction || allied_faction(obj->oward, tm->mfaction))) ||
((obj->oward == EDDER_SYMBOL || obj->oward == XAXOX) && tm->mtyp == PM_EDDERKOP) ||
((tm->mfaction == u.start_house || allied_faction(tm->mfaction,u.start_house)) &&
obj->oward == EDDER_SYMBOL && !(tm->female))
){
if(is_drow(tm->data)) set_faction(tm, EDDER_SYMBOL);
tm->housealert = 1;
tm->mpeaceful = 1;
} else if(is_drow(tm->data) && !(obj->oward == tm->mfaction || allied_faction(obj->oward, tm->mfaction)) && mtmp->female){
tm->housealert = 1;
tm->mpeaceful = 0;
}
}
} else if((obj->oward == mtmp->mfaction || allied_faction(obj->oward, mtmp->mfaction)) ||
(obj->oward == EILISTRAEE_SYMBOL && is_elf(mtmp->data)) ||
((obj->oward == EDDER_SYMBOL || obj->oward == XAXOX) && mtmp->mtyp == PM_EDDERKOP)
){
if(mtmp->housealert && !(mtmp->mpeaceful)){
verbalize("Die, spy!");
for(tm = fmon; tm; tm = tm->nmon){
if((is_drow(tm->data) && (obj->oward == tm->mfaction || allied_faction(obj->oward, tm->mfaction))) ||
((obj->oward == EDDER_SYMBOL || obj->oward == XAXOX) && tm->mtyp == PM_EDDERKOP) ||
(obj->oward == EILISTRAEE_SYMBOL && is_elf(tm->data))
){
tm->housealert = 1;
tm->mpeaceful = 0;
}
}
} else if(flags.female){
if((obj->oward == XAXOX && uarm && uarm->oward && uarm->oward == obj->oward) ||
(obj->oward == EDDER_SYMBOL && uarm && uarm->oward && uarm->oward == obj->oward) ||
!(uarm) || !(uarm->oward) || uarm->oward == obj->oward ||
(
uarm->oward == LOLTH_SYMBOL &&
obj->oward != EILISTRAEE_SYMBOL &&
obj->oward != XAXOX &&
obj->oward != EDDER_SYMBOL
)
){
verbalize("She's one of ours!");
if(obj->oward != XAXOX && obj->oward != EDDER_SYMBOL) verbalize("Apologies, my lady!");
for(tm = fmon; tm; tm = tm->nmon){
if((is_drow(tm->data) && (obj->oward == tm->mfaction || allied_faction(obj->oward, tm->mfaction))) ||
((obj->oward == EDDER_SYMBOL || obj->oward == XAXOX) && tm->mtyp == PM_EDDERKOP) ||
(obj->oward == EILISTRAEE_SYMBOL && is_elf(tm->data))
){
tm->housealert = 1;
tm->mpeaceful = 1;
}
}
} else {
verbalize("Die, spy!");
for(tm = fmon; tm; tm = tm->nmon){
if((is_drow(tm->data) && (obj->oward == tm->mfaction || allied_faction(obj->oward, tm->mfaction))) ||
((obj->oward == EDDER_SYMBOL || obj->oward == XAXOX) && tm->mtyp == PM_EDDERKOP) ||
(obj->oward == EILISTRAEE_SYMBOL && is_elf(tm->data))
){
tm->housealert = 1;
tm->mpeaceful = 0;
}
}
}
} else {
if(((obj->oward <= LAST_TOWER && obj->oward >= FIRST_TOWER) &&
(!(uarm) || !(uarm->oward) || uarm->oward == obj->oward || allied_faction(uarm->oward,obj->oward))) ||
((obj->oward == EDDER_SYMBOL ||
obj->oward == XAXOX ||
obj->oward == GHAUNADAUR_SYMBOL ||
obj->oward == LAST_BASTION_SYMBOL ||
obj->oward == EILISTRAEE_SYMBOL) && (!(uarm) || !(uarm->oward) || uarm->oward == obj->oward || allied_faction(uarm->oward,obj->oward))) ||
(uarm && uarm->oward && uarm->oward == obj->oward)
){
verbalize("He's one of ours!");
verbalize("Move along, sir.");
for(tm = fmon; tm; tm = tm->nmon){
if((is_drow(tm->data) && (obj->oward == tm->mfaction || allied_faction(obj->oward, tm->mfaction))) ||
((obj->oward == EDDER_SYMBOL || obj->oward == XAXOX) && tm->mtyp == PM_EDDERKOP) ||
(obj->oward == EILISTRAEE_SYMBOL && is_elf(tm->data))
){
tm->mpeaceful = 1;
}
}
} else {
verbalize("Die, spy!");
for(tm = fmon; tm; tm = tm->nmon){
if((is_drow(tm->data) && (obj->oward == tm->mfaction || allied_faction(obj->oward, tm->mfaction))) ||
((obj->oward == EDDER_SYMBOL || obj->oward == XAXOX) && tm->mtyp == PM_EDDERKOP) ||
(obj->oward == EILISTRAEE_SYMBOL && is_elf(tm->data))
){
tm->housealert = 1;
tm->mpeaceful = 0;
}
}
}
}
} else {
verbalize("Die!");
mtmp->housealert = 1;
for(tm = fmon; tm; tm = tm->nmon){
if((is_drow(tm->data) && (mtmp->mfaction == tm->mfaction || allied_faction(mtmp->mfaction, tm->mfaction))) ||
((mtmp->mfaction == EDDER_SYMBOL || mtmp->mfaction == XAXOX || tm->mtyp == PM_EDDERKOP) &&
(tm->mfaction == EDDER_SYMBOL || tm->mfaction == XAXOX || tm->mtyp == PM_EDDERKOP)) ||
((mtmp->mfaction == EILISTRAEE_SYMBOL || is_elf(mtmp->data)) &&
(tm->mfaction == EILISTRAEE_SYMBOL || is_elf(tm->data)))
){
tm->housealert = 1;
tm->mpeaceful = 0;
}
}
}
}
}
return MOVE_STANDARD;
}
static int
use_towel(struct obj *obj)
{
if(!freehand()) {
You("have no free %s!", body_part(HAND));
return MOVE_CANCELLED;
} else if (obj->owornmask) {
You("cannot use it while you're wearing it!");
return MOVE_CANCELLED;
} else if (obj->cursed) {
long old;
switch (rn2(3)) {
case 2:
old = Glib;
Glib += rn1(10, 3);
Your("%s %s!", makeplural(body_part(HAND)),
(old ? "are filthier than ever" : "get slimy"));
return MOVE_STANDARD;
case 1:
if (!ublindf) {
old = u.ucreamed;
u.ucreamed += rn1(10, 3);
pline("Yecch! Your %s %s gunk on it!", body_part(FACE),
(old ? "has more" : "now has"));
make_blinded(Blinded + (long)u.ucreamed - old, TRUE);
} else {
const char *what = (ublindf->otyp == LENSES || ublindf->otyp == SUNGLASSES) ? "lenses"
: (ublindf->otyp == SOUL_LENS) ? "lens"
: (ublindf->otyp == MASK || ublindf->otyp == LIVING_MASK || ublindf->otyp == R_LYEHIAN_FACEPLATE) ? "mask" : "blindfold";
if (ublindf->cursed) {
You("push your %s %s.", what,
rn2(2) ? "cock-eyed" : "crooked");
} else {
struct obj *saved_ublindf = ublindf;
You("push your %s off.", what);
Blindf_off(ublindf);
dropx(saved_ublindf);
}
}
return MOVE_STANDARD;
case 0:
break;
}
}
if (Glib) {
Glib = 0;
You("wipe off your %s.", makeplural(body_part(HAND)));
return MOVE_STANDARD;
} else if(u.ucreamed) {
Blinded -= u.ucreamed;
u.ucreamed = 0;
if (!Blinded) {
pline("You've got the glop off.");
Blinded = 1;
make_blinded(0L,TRUE);
} else {
Your("%s feels clean now.", body_part(FACE));
}
return MOVE_STANDARD;
}
Your("%s and %s are already clean.",
body_part(FACE), makeplural(body_part(HAND)));
return MOVE_CANCELLED;
}
/* maybe give a stethoscope message based on floor objects */
static boolean
its_dead(int rx, int ry, int *resp, struct obj *tobj)
{
struct obj *otmp;
struct trap *ttmp;
if (!can_reach_floor()) return FALSE;
/* additional stethoscope messages from jyoung@apanix.apana.org.au */
if (Hallucination && sobj_at(CORPSE, rx, ry)) {
/* (a corpse doesn't retain the monster's sex,
so we're forced to use generic pronoun here) */
You_hear("a voice say, \"It's dead, Jim.\"");
*resp = 1;
return TRUE;
} else if (Role_if(PM_HEALER) && ((otmp = sobj_at(CORPSE, rx, ry)) != 0 ||
(otmp = sobj_at(STATUE, rx, ry)) != 0 || (otmp = sobj_at(FOSSIL, rx, ry)) != 0)) {
/* possibly should check uppermost {corpse,statue} in the pile
if both types are present, but it's not worth the effort */
if (vobj_at(rx, ry)->otyp == STATUE) otmp = vobj_at(rx, ry);
if (otmp->otyp == CORPSE || otmp->otyp == FOSSIL) {
You("determine that %s unfortunate being is %sdead.",
(rx == u.ux && ry == u.uy) ? "this" : "that", (otmp->otyp == FOSSIL) ? "very ":"");
} else {
ttmp = t_at(rx, ry);
pline("%s appears to be in %s health for a statue.",
The(mons[otmp->corpsenm].mname),
(ttmp && ttmp->ttyp == STATUE_TRAP) ?
"extraordinary" : "excellent");
}
return TRUE;
}
/* listening to eggs is a little fishy, but so is stethoscopes detecting alignment
* The overcomplex wording is because all the monster-naming functions operate
* on actual instances of the monsters, and we're dealing with just an index
* so we can avoid things like "a owlbear", etc. */
if ((otmp = sobj_at(EGG,rx,ry))) {
if (Hallucination) {
pline("You listen to the egg and guess... %s?",rndmonnam());
} else {
if (stale_egg(otmp) || otmp->corpsenm == NON_PM) {
pline("The egg doesn't make much noise at all.");
} else {
pline("You listen to the egg and guess... %s?",mons[otmp->corpsenm].mname);
learn_egg_type(otmp->corpsenm);
}
}
return TRUE;
}
return FALSE;
}
static const char hollow_str[] = "a hollow sound. This must be a secret %s!";
/* Strictly speaking it makes no sense for usage of a stethoscope to
not take any time; however, unless it did, the stethoscope would be
almost useless. As a compromise, one use per turn is free, another
uses up the turn; this makes curse status have a tangible effect. */
static int
use_stethoscope(register struct obj *obj)
{
struct monst *mtmp;
struct rm *lev;
int rx, ry, res;
boolean interference = (u.uswallow && is_whirly(u.ustuck->data) &&
!rn2(Role_if(PM_HEALER) ? 10 : 3));
if (nohands(youracedata)) { /* should also check for no ears and/or deaf */
You("have no hands!"); /* not `body_part(HAND)' */
return MOVE_CANCELLED;
} else if (!freehand()) {
You("have no free %s.", body_part(HAND));
return MOVE_CANCELLED;
}
if (!getdir((char *)0)) return MOVE_CANCELLED;
res = MOVE_PARTIAL;
if (u.usteed && u.dz > 0) {
if (interference) {
pline("%s interferes.", Monnam(u.ustuck));
mstatusline(u.ustuck);
} else
mstatusline(u.usteed);
return res;
} else
if (u.uswallow && (u.dx || u.dy || u.dz)) {
mstatusline(u.ustuck);
return res;
} else if (u.uswallow && interference) {
pline("%s interferes.", Monnam(u.ustuck));
mstatusline(u.ustuck);
return res;
} else if (u.dz) {
if (Underwater)
You_hear("faint splashing.");
else if (u.dz < 0 || !can_reach_floor())
You_cant("reach the %s.",
(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
else if (its_dead(u.ux, u.uy, &res, obj))
; /* message already given */
else if (Is_stronghold(&u.uz))
You_hear("the crackling of hellfire.");
else
pline_The("%s seems healthy enough.", surface(u.ux,u.uy));
return res;
} else if (obj->cursed && !rn2(2)) {
You_hear("your %s %s.", body_part(HEART), body_part(BEAT));
return res;
}
if (Stunned || (Confusion && !rn2(5))) confdir();
if (!u.dx && !u.dy) {
ustatusline();
return res;
}
rx = u.ux + u.dx; ry = u.uy + u.dy;
if (!isok(rx,ry)) {
You_hear("a faint typing noise.");
return MOVE_INSTANT;
}
if ((mtmp = m_at(rx,ry)) != 0) {
mstatusline(mtmp);
if (mtmp->mundetected) {
mtmp->mundetected = 0;
if (cansee(rx,ry)) newsym(mtmp->mx,mtmp->my);
}
if (!canspotmon(mtmp))
map_invisible(rx,ry);
return res;
}
if (glyph_is_invisible(levl[rx][ry].glyph)) {
unmap_object(rx, ry);
newsym(rx, ry);
pline_The("invisible monster must have moved.");
}
lev = &levl[rx][ry];
switch(lev->typ) {
case SDOOR:
You_hear(hollow_str, "door");
cvt_sdoor_to_door(lev); /* ->typ = DOOR */
if (Blind) feel_location(rx,ry);
else newsym(rx,ry);
return res;
case SCORR:
You_hear(hollow_str, "passage");
lev->typ = CORR;
unblock_point(rx,ry);
if (Blind) feel_location(rx,ry);
else newsym(rx,ry);
return res;
}
if (!its_dead(rx, ry, &res, obj))
You_hear("nothing special."); /* not You_hear() */
return res;
}
static const char whistle_str[] = "produce a %s whistling sound.";
static void
use_whistle(struct obj *obj)
{
register struct monst *mtmp;
You(whistle_str, obj->cursed ? "shrill" : "high");
wake_nearby_noisy();
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (!DEADMONSTER(mtmp)) {
if (get_mx(mtmp, MX_EDOG))
EDOG(mtmp)->whistletime = moves;
}
}
makeknown(obj->otyp); /* the messages are all unique */
}
void
use_magic_whistle(struct obj *obj)
{
register struct monst *mtmp, *nextmon;
if(obj->cursed && !rn2(2)) {
You("produce a high-pitched humming noise.");
wake_nearby();
} else {
You(whistle_str, Hallucination ? "normal" : "strange");
for(mtmp = fmon; mtmp; mtmp = nextmon) {
nextmon = mtmp->nmon; /* trap might kill mon */
if (DEADMONSTER(mtmp)) continue;
if (mtmp->mtame) {
if (mtmp->mtrapped) {
/* no longer in previous trap (affects mintrap) */
mtmp->mtrapped = 0;
fill_pit(mtmp->mx, mtmp->my);
}
mnexto(mtmp);
if (mintrap(mtmp) == 2) change_luck(-1);
}
}
}
makeknown(obj->otyp); /* the messages are all unique */
}
boolean
um_dist(xchar x, xchar y, xchar n)
{
return((boolean)(abs(u.ux - x) > n || abs(u.uy - y) > n));
}
int
number_leashed(void)
{
register int i = 0;
register struct obj *obj;
for(obj = invent; obj; obj = obj->nobj)
if(obj->otyp == LEASH && obj->leashmon != 0) i++;
return(i);
}
/* otmp is about to be destroyed or stolen */
void
o_unleash(register struct obj *otmp)
{
register struct monst *mtmp;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if(mtmp->m_id == (unsigned)otmp->leashmon)
mtmp->mleashed = 0;
otmp->leashmon = 0;
}
/* mtmp is about to die, or become untame */
void
m_unleash(register struct monst *mtmp, boolean feedback)
{
register struct obj *otmp;
if (feedback) {
if (canseemon(mtmp))
pline("%s pulls free of %s leash!", Monnam(mtmp), mhis(mtmp));
else
Your("leash falls slack.");
}
for(otmp = invent; otmp; otmp = otmp->nobj)
if(otmp->otyp == LEASH &&
otmp->leashmon == (int)mtmp->m_id)
otmp->leashmon = 0;
mtmp->mleashed = 0;
}
void
unleash_all(void) /* player is about to die (for bones) */
{
register struct obj *otmp;
register struct monst *mtmp;
for(otmp = invent; otmp; otmp = otmp->nobj)
if(otmp->otyp == LEASH) otmp->leashmon = 0;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
mtmp->mleashed = 0;
}
#define MAXLEASHED 2
/* ARGSUSED */
static void
use_leash(struct obj *obj)
{
coord cc;
register struct monst *mtmp;
int spotmon;
if(!obj->leashmon && number_leashed() >= MAXLEASHED) {
You("cannot leash any more pets.");
return;
}
if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return;
if((cc.x == u.ux) && (cc.y == u.uy)) {
if (u.usteed && u.dz > 0) {
mtmp = u.usteed;
spotmon = 1;
goto got_target;
}
pline("Leash yourself? Very funny...");
return;
}
if(!(mtmp = m_at(cc.x, cc.y))) {
There("is no creature there.");
return;
}
spotmon = canspotmon(mtmp);
got_target:
if(!mtmp->mtame) {
if(!spotmon)
There("is no creature there.");
else
pline("%s %s leashed!", Monnam(mtmp), (!obj->leashmon) ?
"cannot be" : "is not");
return;
}
if(!obj->leashmon) {
if(mtmp->mleashed) {
pline("This %s is already leashed.",
spotmon ? l_monnam(mtmp) : "monster");
return;
}
You("slip the leash around %s%s.",
spotmon ? "your " : "", l_monnam(mtmp));
mtmp->mleashed = 1;
obj->leashmon = (int)mtmp->m_id;
mtmp->msleeping = 0;
return;
}
if(obj->leashmon != (int)mtmp->m_id) {
pline("This leash is not attached to that creature.");
return;
} else {
if(obj->cursed) {
pline_The("leash would not come off!");
obj->bknown = TRUE;
return;
}
mtmp->mleashed = 0;
obj->leashmon = 0;
You("remove the leash from %s%s.",
spotmon ? "your " : "", l_monnam(mtmp));
}
return;
}
/* assuming mtmp->mleashed has been checked */
struct obj *
get_mleash(register struct monst *mtmp)
{
register struct obj *otmp;
otmp = invent;
while(otmp) {
if(otmp->otyp == LEASH && otmp->leashmon == (int)mtmp->m_id)
return(otmp);
otmp = otmp->nobj;
}
return((struct obj *)0);
}
boolean
next_to_u(void)
{
register struct monst *mtmp;
register struct obj *otmp;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp)) continue;
if(mtmp->mleashed) {
if (distu(mtmp->mx,mtmp->my) > 2) mnexto(mtmp);
if (distu(mtmp->mx,mtmp->my) > 2) {
for(otmp = invent; otmp; otmp = otmp->nobj)
if(otmp->otyp == LEASH &&
otmp->leashmon == (int)mtmp->m_id) {
if(otmp->cursed) return(FALSE);
You_feel("%s leash go slack.",
(number_leashed() > 1) ? "a" : "the");
mtmp->mleashed = 0;
otmp->leashmon = 0;
}
}
}
}
/* no pack mules for the Amulet */
if (u.usteed && mon_has_amulet(u.usteed)) return FALSE;
return(TRUE);
}
void
check_leash(xchar x, xchar y)
{
register struct obj *otmp;
register struct monst *mtmp;
for (otmp = invent; otmp; otmp = otmp->nobj) {
if (otmp->otyp != LEASH || otmp->leashmon == 0) continue;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp)) continue;
if ((int)mtmp->m_id == otmp->leashmon) break;
}
if (!mtmp) {
impossible("leash in use isn't attached to anything?");
otmp->leashmon = 0;
continue;
}
if (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) >
dist2(x,y,mtmp->mx,mtmp->my)) {
if (!um_dist(mtmp->mx, mtmp->my, 3)) {
; /* still close enough */
} else if (otmp->cursed && !breathless_mon(mtmp)) {
if (um_dist(mtmp->mx, mtmp->my, 5) ||
(mtmp->mhp -= rnd(2)) <= 0) {
long save_pacifism = u.uconduct.killer;
Your("leash chokes %s to death!", mon_nam(mtmp));
/* hero might not have intended to kill pet, but
that's the result of his actions; gain experience,
lose pacifism, take alignment and luck hit, make
corpse less likely to remain tame after revival */
xkilled(mtmp, 0); /* no "you kill it" message */
/* life-saving doesn't ordinarily reset this */
if (mtmp->mhp > 0) u.uconduct.killer = save_pacifism;
} else {
pline("%s chokes on the leash!", Monnam(mtmp));
/* tameness eventually drops to 1 here (never 0) */
if (mtmp->mtame && rn2(mtmp->mtame)) mtmp->mtame--;
if(mtmp->mtyp == PM_CROW && u.sealsActive&SEAL_MALPHAS) unbind(SEAL_MALPHAS,TRUE);
}
} else {
if (um_dist(mtmp->mx, mtmp->my, 5)) {
pline("%s leash snaps loose!", s_suffix(Monnam(mtmp)));
m_unleash(mtmp, FALSE);
} else {
You("pull on the leash.");
if (!is_silent_mon(mtmp))
switch (rn2(3)) {
case 0: growl(mtmp); break;
case 1: yelp(mtmp); break;
default: whimper(mtmp); break;
}
}
}
}
}
}
#define WEAK 3 /* from eat.c */
static const char look_str[] = "look %s.";
static int
use_mirror(struct obj **obj_p)
{
register struct monst *mtmp;
register char mlet;
boolean vis;
struct obj *obj = *obj_p;
if(!getdir((char *)0)) return MOVE_CANCELLED;
if(obj->cursed && !rn2(2)) {
if (!Blind)
pline_The("mirror fogs up and doesn't reflect!");
return MOVE_STANDARD;
}
if(!u.dx && !u.dy && !u.dz) {
if(obj->oartifact == ART_HAND_MIRROR_OF_CTHYLLA && obj->age < moves && !Blind){
pline("An incomprehensible sight meets your eyes!");
losehp(d(15,15), "looking into Cthylla's hand-mirror", KILLED_BY);
obj->age = monstermoves + (long)(rnz(100)*(Role_if(PM_PRIEST) ? .8 : 1));
} else if(!Blind) {
if (youracedata->mlet == S_VAMPIRE || Invisible) {
You("don't have a reflection.");
vis = FALSE;
} else if (u.umonnum == PM_FLOATING_EYE && ward_at(u.ux, u.uy) != HAMSA) {
if (!Free_action) {
pline("%s", Hallucination ?
"Yow! The mirror stares back!" :
"Yikes! You've frozen yourself!");
nomul(-d(2,6), "frozen by your own reflection");
vis = FALSE;
}
else {
You("stiffen momentarily under your gaze.");
vis = TRUE;
}
} else if (u.umonnum == PM_UMBER_HULK && ward_at(u.ux, u.uy) != HAMSA) {
pline("Huh? That doesn't look like you!");
make_confused(HConfusion + d(3,4),FALSE);
vis = FALSE;
} else if (u.sealsActive&SEAL_IRIS){
pline("What? Who is that in the mirror!?");
unbind(SEAL_IRIS,TRUE);
vis = FALSE;
} else if (roll_madness(MAD_ARGENT_SHEEN)) {
You("admire your reflection in the mirror.");
nomul(-1*rnd(6), "posing in front of a mirror.");
vis = FALSE;
} else if (Hallucination) {
You(look_str, hcolor((char *)0));
vis = TRUE;
} else if (Sick) {
You(look_str, "peaked");
vis = TRUE;
} else if (u.uhs >= WEAK) {
You(look_str, "undernourished");
vis = TRUE;
} else {
You("look as %s as ever.",
ACURR(A_CHA) > 14 ?
(poly_gender() == 1 ? "beautiful" : "handsome") :
"ugly");
vis = TRUE;
}
if (vis){
signs_mirror();
}
if(u.uinsight >= 10 && !obj->oartifact){
// if(wizard)
// pline("silver flame d: %d, l: %d, x:%d, y:%d", u.silver_flame_z.dnum, u.silver_flame_z.dlevel, u.s_f_x, u.s_f_y);
if(u.uz.dnum == u.silver_flame_z.dnum){
if(u.silver_flame_z.dlevel > u.uz.dlevel){
if(!u.silver_atten)
You("notice a silver light %sbelow you.", ((u.silver_flame_z.dlevel-u.uz.dlevel) > 10) ? "deep " : "");
}
else if(u.silver_flame_z.dlevel < u.uz.dlevel){
if(!u.silver_atten)
You("notice a silver light %sabove you.", ((u.silver_flame_z.dlevel-u.uz.dlevel) > 10) ? "high " : "");
}
else {
int dx = u.ux - u.s_f_x,
dy = u.uy - u.s_f_y;
int absx = abs(dx),
absy = abs(dy);
if(!dx && !dy){
if(u.silver_atten)
You("have returned to the silver flame.");
else
pline("A volcanic pillar of silver flame spouts forth here, rising arrow-straight from the profound and inconceivable depths to the empty and unknown heavens!");
if(yn("Offer an implement to the fire?") == 'y'){
const char sflm_classes[] = { WEAPON_CLASS, TOOL_CLASS, ARMOR_CLASS, 0 };
struct obj *sflm_obj = getobj(sflm_classes, "offer to the flame");
if(sflm_obj){
if(sflm_offerable(sflm_obj)){
pline("The silver light reflects from your mirror and takes up residence within %s.", doname(sflm_obj));
add_oprop(sflm_obj, OPROP_SFLMW);
u.silver_atten = TRUE;
*obj_p = poly_obj(obj, PURIFIED_MIRROR);
}
else pline("Nothing happens.");
}
}
}
else if(absx <= 4 && absy <= 4){
if(absx && absy){
You("see a column of silver fire %d step%s %s and %d step%s %s.", absx, absx > 1 ? "s" : "", dx > 0 ? "west" : "east",
absy, absy > 1 ? "s" : "", dy > 0 ? "north" : "south");
}
else {
//Note: One of the distances is 0, figure out which one isn't
int absd = absx ? absx : absy;
You("see a column of silver fire %d step%s %s.", absd, absd > 1 ? "s" : "", dx > 0 ? "west" : dx < 0 ? "east" : dy > 0 ? "north" : "south");
}
}
else {
char *distword = (absx > 10 || absy > 10) ? "far " : "";
char *dirword;
//Note: at least one of absx and absy is > 0 (> 4 in fact)
if(dy > 0){
//North, or maybe east or west
if(absy > 2*absx)
dirword = "north";
else if(absx > 2*absy){
if(dx > 0)
dirword = "west";
else
dirword = "east";
}
else {
if(dx > 0)
dirword = "north-west";
else
dirword = "north-east";
}
}
else {
//South, or maybe east or west
if(absy > 2*absx)
dirword = "south";
else if(absx > 2*absy){
if(dx > 0)
dirword = "west";
else
dirword = "east";
}
else {
if(dx > 0)
dirword = "south-west";
else
dirword = "south-east";
}
}
You("notice a silver light %sto the %s.", distword, dirword);
}
}
}
}
} else {
You_cant("see your %s %s.",
ACURR(A_CHA) > 14 ?
(poly_gender()==1 ? "beautiful" : "handsome") :
"ugly",
body_part(FACE));
}
return MOVE_STANDARD;
}
if(u.uswallow) {
if (!Blind) You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)),
mbodypart(u.ustuck, STOMACH));
return MOVE_STANDARD;
}
if(Underwater) {
You(Hallucination ?
"give the fish a chance to fix their makeup." :
"reflect the murky water.");
return MOVE_STANDARD;
}
if(u.dz) {
if (!Blind)
You("reflect the %s.",
(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
return MOVE_STANDARD;
}
mtmp = bhit(u.dx, u.dy, COLNO, INVIS_BEAM,
(int (*)(struct monst *,struct obj *))0,
(int (*)(struct obj *,struct obj *))0,
obj, NULL);
if (!mtmp || !haseyes(mtmp->data))
return MOVE_STANDARD;
vis = canseemon(mtmp);
mlet = mtmp->data->mlet;
if (mtmp->msleeping) {
if (vis)
pline ("%s is too tired to look at your mirror.",
Monnam(mtmp));
} else if (is_blind(mtmp)) {
if (vis)
pline("%s can't see anything right now.", Monnam(mtmp));
/* some monsters do special things */
} else if (mlet == S_VAMPIRE || mlet == S_GHOST || mlet == S_SHADE) {
if (vis)
pline ("%s doesn't have a reflection.", Monnam(mtmp));
} else if(obj->oartifact == ART_HAND_MIRROR_OF_CTHYLLA && obj->age < moves &&
(!mtmp->minvis || mon_resistance(mtmp,SEE_INVIS))
){
obj->age = monstermoves + (long)(rnz(100)*(Role_if(PM_PRIEST) ? .8 : 1));
if (vis)
pline("%s is blasted by its reflection.", Monnam(mtmp));
monflee(mtmp, d(2,4), FALSE, FALSE);
mtmp->mhp -= d(15,15);
if (mtmp->mhp <= 0){
mtmp->mhp = 0;
xkilled(mtmp, 1);
}
} else if(!mtmp->mcan && !mtmp->minvis &&
mtmp->mtyp == PM_MEDUSA &&
ward_at(mtmp->mx,mtmp->my) != HAMSA) {
if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!"))
return MOVE_STANDARD;
minstapetrify(mtmp, TRUE);
} else if(!mtmp->mcan && !mtmp->minvis &&
mtmp->mtyp == PM_FLOATING_EYE &&
ward_at(mtmp->mx,mtmp->my) != HAMSA) {
int tmp = d(min(MAX_BONUS_DICE, (int)mtmp->m_lev), (int)mtmp->data->mattk[0].damd);
if (!rn2(4)) tmp = 120;
if (vis)
pline("%s is frozen by its reflection.", Monnam(mtmp));
else You_hear("%s stop moving.",something);
mtmp->mcanmove = 0;
if ( (int) mtmp->mfrozen + tmp > 127)
mtmp->mfrozen = 127;
else mtmp->mfrozen += tmp;
} else if(!mtmp->mcan && !mtmp->minvis &&
mtmp->mtyp == PM_UMBER_HULK &&
ward_at(mtmp->mx,mtmp->my) != HAMSA) {
if (vis)
pline ("%s confuses itself!", Monnam(mtmp));
mtmp->mconf = 1;
} else if(!mtmp->mcan && !mtmp->minvis && (mlet == S_NYMPH
|| mtmp->mtyp==PM_SUCCUBUS)) {
if (vis) {
pline ("%s admires herself in your mirror.", Monnam(mtmp));
pline ("She takes it!");
} else pline ("It steals your mirror!");
setnotworn(obj); /* in case mirror was wielded */
freeinv(obj);
(void) mpickobj(mtmp,obj);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE);
} else if(!mtmp->mcan && !mtmp->minvis && is_weeping(mtmp->data)) {
if (vis)
pline ("%s stares at its reflection with a stony expression.", Monnam(mtmp));
mtmp->mcanmove = 0;
mtmp->mfrozen = 1;
} else if (!is_unicorn(mtmp->data) && is_animal(mtmp->data) &&
(!mtmp->minvis || mon_resistance(mtmp,SEE_INVIS)) && rn2(5)) {
if (vis)
pline("%s is frightened by its reflection.", Monnam(mtmp));
monflee(mtmp, d(2,4), FALSE, FALSE);
} else if (!Blind) {
if (mtmp->minvis && !See_invisible(mtmp->mx, mtmp->my))
;
else if ((mtmp->minvis && !mon_resistance(mtmp,SEE_INVIS))
|| !haseyes(mtmp->data))
pline("%s doesn't seem to notice its reflection.",
Monnam(mtmp));
else
pline("%s ignores %s reflection.",
Monnam(mtmp), mhis(mtmp));
}
return MOVE_STANDARD;
}
void
use_bell(struct obj **optr, int spiritseal)
{
register struct obj *obj = *optr;
struct monst *mtmp;
boolean wakem = FALSE, learno = FALSE,
ordinary = (obj->otyp != BELL_OF_OPENING || (!obj->spe && !spiritseal)),
invoking = (obj->otyp == BELL_OF_OPENING &&
(spiritseal ?
((invocation_pos(obj->ox, obj->oy) && !On_stairs(obj->ox, obj->oy)) || (invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy))) :
(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy))
));
if(!spiritseal) You("ring %s.", the(xname(obj)));
if(Role_if(PM_EXILE) && obj->otyp == BELL_OF_OPENING && !spiritseal){
pline("It makes a rather sad clonk.");
return;
}
if (Underwater || (u.uswallow && ordinary)) {
pline("But the sound is muffled.");
} else if (invoking && ordinary) {
/* needs to be recharged... */
pline("But it makes no sound.");
learno = TRUE; /* help player figure out why */
} else if (ordinary) {
if (obj->cursed && !rn2(4) &&
/* note: once any of them are gone, we stop all of them */
!(mvitals[PM_DRYAD].mvflags & G_GONE && !In_quest(&u.uz)) &&
!(mvitals[PM_NAIAD].mvflags & G_GONE && !In_quest(&u.uz)) &&
!(mvitals[PM_OREAD].mvflags & G_GONE && !In_quest(&u.uz)) &&
(mtmp = makemon(mkclass(S_NYMPH, Inhell ? G_HELL : G_NOHELL),
u.ux, u.uy, NO_MINVENT)) != 0) {
You("summon %s!", a_monnam(mtmp));
if (!obj_resists(obj, 0, 100)) {
pline("%s shattered!", Tobjnam(obj, "have"));
useup(obj);
*optr = 0;
} else switch (rn2(3)) {
default:
break;
case 1:
mon_adjust_speed(mtmp, 2, (struct obj *)0, TRUE);
break;
case 2: /* no explanation; it just happens... */
nomovemsg = "";
nomul(-rnd(2), "ringing a bell");
break;
}
}
wakem = TRUE;
} else {
/* charged Bell of Opening */
consume_obj_charge(obj, TRUE);
if(uwep && uwep->oartifact == ART_SINGING_SWORD){
uwep->ovar1_heard |= OHEARD_OPEN;
}
if (u.uswallow) {
if (!obj->cursed)
(void) openit();
else
pline("%s", nothing_happens);
} else if (obj->cursed) {
coord mm;
mm.x = u.ux;
mm.y = u.uy;
pline("Graves open around you...");
mkundead(&mm, FALSE, NO_MINVENT, 0);
wakem = TRUE;
} else if (invoking) {
pline("%s an unsettling shrill sound...",
Tobjnam(obj, "issue"));
if(spiritseal && !obj->cursed) u.rangBell = moves;
obj->age = moves;
learno = TRUE;
wakem = TRUE;
} else if (obj->blessed) {
int res = 0;
if (uchain) {
unpunish();
res = 1;
}
res += openit();
switch (res) {
case 0: pline("%s", nothing_happens); break;
case 1: pline("%s opens...", Something);
learno = TRUE; break;
default: pline("Things open around you...");
learno = TRUE; break;
}
} else { /* uncursed */
if (findit() != 0) learno = TRUE;
else pline("%s", nothing_happens);
}
} /* charged BofO */
if (learno) {
makeknown(BELL_OF_OPENING);
obj->known = 1;
}
if (wakem) wake_nearby_noisy();
}
static void
use_candelabrum(register struct obj *obj)
{
const char *s = (obj->spe != 1) ? "candles" : "candle";
if(Underwater) {
You("cannot make fire under water.");
return;
}
if(obj->lamplit) {
You("snuff the %s.", s);
end_burn(obj, TRUE);
return;
}
if(obj->spe <= 0) {
pline("This %s has no %s.", xname(obj), s);
return;
}
if(u.uswallow || obj->cursed) {
if (!Blind)
pline_The("%s %s for a moment, then %s.",
s, vtense(s, "flicker"), vtense(s, "die"));
return;
}
if(obj->spe < 7) {
There("%s only %d %s in %s.",
vtense(s, "are"), obj->spe, s, the(xname(obj)));
if (!Blind)
pline("%s lit. %s dimly.",
obj->spe == 1 ? "It is" : "They are",
Tobjnam(obj, "shine"));
} else {
pline("%s's %s burn%s", The(xname(obj)), s,
(Blind ? "." : " brightly!"));
}
if (!invocation_pos(u.ux, u.uy)) {
pline_The("%s %s being rapidly consumed!", s, vtense(s, "are"));
/* this used to be obj->age /= 2, rounding down; an age of
1 would yield 0, confusing begin_burn() and producing an
unlightable, unrefillable candelabrum; round up instead */
obj->age = (obj->age + 1L) / 2L;
/* to make absolutely sure the game doesn't become unwinnable as
a consequence of a broken candelabrum */
if (obj->age == 0) {
impossible("Candelabrum with candles but no fuel?");
obj->age = 1;
}
} else {
if(obj->spe == 7) {
if (Blind)
pline("%s a strange warmth!", Tobjnam(obj, "radiate"));
else
pline("%s with a strange light!", Tobjnam(obj, "glow"));
}
obj->known = 1;
}
begin_burn(obj);
}
static void
use_candle(struct obj **optr)
{
register struct obj *obj = *optr;
register struct obj *otmp;
const char *s = (obj->quan != 1) ? "candles" : "candle";
char qbuf[QBUFSZ];
boolean was_lamplit;
if (u.uswallow){
if(!is_whirly(u.ustuck->data)) {
You(no_elbow_room);
return;
} else if(!obj->lamplit){
You("can't get the %s to light. It's quite hopeless under these conditions.", s);
return;
}
}
if(Underwater) {
pline("Sorry, fire and water don't mix.");
return;
}
otmp = carrying(CANDELABRUM_OF_INVOCATION);
if(!otmp || obj->otyp==GNOMISH_POINTY_HAT || obj->otyp==CANDLE_OF_INVOCATION || otmp->spe == 7) {
use_lamp(obj);
return;
}
Sprintf(qbuf, "Attach %s", the(xname(obj)));
Sprintf(eos(qbuf), " to %s?",
safe_qbuf(qbuf, sizeof(" to ?"), the(xname(otmp)),
the(simple_typename(otmp->otyp)), "it"));
if(yn(qbuf) == 'n') {
if (!obj->lamplit)
You("try to light %s...", the(xname(obj)));
use_lamp(obj);
return;
} else {
if ((long)otmp->spe + obj->quan > 7L)
obj = splitobj(obj, 7L - (long)otmp->spe);
else *optr = 0;
/* The candle's age field doesn't correctly reflect the amount
of fuel in it while it's lit, because the fuel is measured
by the timer. So to get accurate age updating, we need to
end the burn temporarily while attaching the candle. */
was_lamplit = obj->lamplit;
if (was_lamplit)
end_burn(obj, TRUE);
You("attach %ld%s %s to %s.",
obj->quan, !otmp->spe ? "" : " more",
s, the(xname(otmp)));
if (!otmp->spe || otmp->age > obj->age)
otmp->age = obj->age;
otmp->spe += (int)obj->quan;
if (otmp->lamplit && !was_lamplit)
pline_The("new %s magically %s!", s, vtense(s, "ignite"));
else if (!otmp->lamplit && was_lamplit)
pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes");
if (obj->unpaid)
verbalize("You %s %s, you bought %s!",
otmp->lamplit ? "burn" : "use",
(obj->quan > 1L) ? "them" : "it",
(obj->quan > 1L) ? "them" : "it");
if (obj->quan < 7L && otmp->spe == 7)
pline("%s now has seven%s candles attached.",
The(xname(otmp)), otmp->lamplit ? " lit" : "");
/* candelabrum's light range might increase */
if (otmp->lamplit) obj_merge_light_sources(otmp, otmp);
/* candles are no longer a separate light source */
/* candles are now gone */
useupall(obj);
}
}
boolean
snuff_candle( /* call in drop, throw, and put in box, etc. */
register struct obj *otmp)
{
register boolean candle = Is_candle(otmp);
if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION) &&
otmp->lamplit) {
char buf[BUFSZ];
xchar x, y;
register boolean many = candle ? otmp->quan > 1L : otmp->spe > 1;
(void) get_obj_location(otmp, &x, &y, 0);
if (otmp->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
pline("%s %scandle%s flame%s extinguished.",
Shk_Your(buf, otmp),
(candle ? "" : "candelabrum's "),
(many ? "s'" : "'s"), (many ? "s are" : " is"));
end_burn(otmp, TRUE);
return(TRUE);
}
return(FALSE);
}
/* called when lit lamp is hit by water or put into a container or
you've been swallowed by a monster; obj might be in transit while
being thrown or dropped so don't assume that its location is valid */
boolean
snuff_lit(struct obj *obj)
{
xchar x, y;
if (obj->lamplit) {
if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
obj->otyp == LANTERN || obj->otyp == LANTERN_PLATE_MAIL ||
obj->otyp == POT_OIL ||
obj->otyp == DWARVISH_HELM || obj->otyp == GNOMISH_POINTY_HAT) {
(void) get_obj_location(obj, &x, &y, 0);
if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
pline("%s %s out!", Yname2(obj), otense(obj, "go"));
end_burn(obj, TRUE);
return TRUE;
}
if (snuff_candle(obj)) return TRUE;
}
return FALSE;
}
/* Called when potentially lightable object is affected by fire_damage().
Return TRUE if object was lit and FALSE otherwise --ALI */
boolean
catch_lit(struct obj *obj)
{
xchar x, y;
if (!obj->lamplit && ignitable(obj)) {
if ((obj->otyp == MAGIC_LAMP ||
obj->otyp == CANDELABRUM_OF_INVOCATION) &&
obj->spe == 0)
return FALSE;
else if (obj->otyp != MAGIC_LAMP && obj->age == 0)
return FALSE;
if (!get_obj_location(obj, &x, &y, 0))
return FALSE;
if (obj->otyp == CANDELABRUM_OF_INVOCATION && obj->cursed)
return FALSE;
if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
obj->otyp == LANTERN || obj->otyp == LANTERN_PLATE_MAIL ||
obj->otyp == DWARVISH_HELM || obj->otyp == GNOMISH_POINTY_HAT) &&
obj->cursed && !rn2(2))
return FALSE;
if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
pline("%s %s light!", Yname2(obj), otense(obj, "catch"));
if (obj->otyp == POT_OIL) makeknown(obj->otyp);
if (obj->unpaid && costly_spot(u.ux, u.uy) && (obj->where == OBJ_INVENT)) {
/* if it catches while you have it, then it's your tough luck */
check_unpaid(obj);
verbalize("That's in addition to the cost of %s %s, of course.",
Yname2(obj), obj->quan == 1 ? "itself" : "themselves");
bill_dummy_object(obj);
}
begin_burn(obj);
return TRUE;
}
return FALSE;
}
static int
swap_aegis(struct obj *obj)
{
if(obj->owornmask){
You("must take %s off to modify it.", the(xname(obj)));
return MOVE_CANCELLED;
} else if(obj->otyp == CLOAK){
You("wrap %s up, making a serviceable shield.", the(xname(obj)));
obj->otyp = ROUNDSHIELD;
return MOVE_STANDARD;
} else if(obj->otyp == ROUNDSHIELD){
You("unwrap %s, making a cloak.", the(xname(obj)));
obj->otyp = CLOAK;
return MOVE_STANDARD;
} else {
pline("Aegis in unexpected state?");
return MOVE_CANCELLED;
}
}
static int
ilmater_touch(struct obj *obj)
{
struct monst *mon;
// Allow the cords to be used from inventory, like a unicorn horn or a stethoscope.
if(!getdir((char *)0)) {
return MOVE_CANCELLED;
}
if(u.dz > 0){
if(u.usteed)
mon = u.usteed;
else if(u.uswallow)
mon = u.ustuck;
else {
You("doubt that will have any further effect.");
return MOVE_CANCELLED;
}
}
else if(u.dz < 0){
if(u.uswallow)
mon = u.ustuck;
else {
You("don't see anything up there to touch with your cords.");
return MOVE_CANCELLED;
}
}
else if(!u.dx && !u.dy){
if(*hp(&youmonst) >= *hpmax(&youmonst))
pline("Nothing happens.");
else
You("transfer your wounds to yourself.");
return MOVE_STANDARD;
}
else if(!isok(u.ux + u.dx, u.uy + u.dy)){
You("don't touch anything.");
return MOVE_STANDARD;
}
else {
mon = m_at(u.ux + u.dx, u.uy + u.dy);
}
if(!mon){
You("don't touch anything.");
return MOVE_STANDARD;
}
if(mon->mpeaceful){
if(*hp(mon) >= *hpmax(mon))
pline("Nothing happens.");
else {
You("transfer %s wounds to yourself.", s_suffix(mon_nam(mon)));
int wounds = *hpmax(mon) - *hp(mon);
wounds = min(wounds, *hp(&youmonst)/2);
*hp(mon) += wounds;
*hp(&youmonst) -= wounds;
flags.botl = 1;
}
return MOVE_STANDARD;
}
else {
if(*hp(&youmonst) >= *hpmax(&youmonst))
pline("Nothing happens.");
else {
You("transfer your wounds to %s.", mon_nam(mon));
int wounds = *hpmax(&youmonst) - *hp(&youmonst);
wounds = min(wounds, *hp(mon)/2);
*hp(&youmonst) += wounds;
*hp(mon) -= wounds;
flags.botl = 1;
}
return MOVE_STANDARD;
}
return MOVE_STANDARD;
}
static int
aesculapius_poke(struct obj *obj)
{
struct monst *mon;
boolean shackles = obj->oartifact == ART_ESSCOOAHLIPBOOURRR;
if(obj != uwep){
if (!wield_tool(obj, "staff")) return MOVE_CANCELLED;
}
if(!getdir((char *)0)) {
return MOVE_CANCELLED;
}
if(u.dz > 0){
if(u.usteed)
mon = u.usteed;
else if(u.uswallow)
mon = u.ustuck;
else {
You("doubt that will have any further effect.");
return MOVE_CANCELLED;
}
}
else if(u.dz < 0){
if(u.uswallow)
mon = u.ustuck;
else {
if(shackles)
You("don't see anything up there to touch with your broken shackles.");
else
You("don't see anything up there to poke with your staff.");
return MOVE_CANCELLED;
}
}
else if(!u.dx && !u.dy){
use_unicorn_horn(obj);
return MOVE_STANDARD;
}
else if(!isok(u.ux + u.dx, u.uy + u.dy)){
if(shackles)
pline("Your broken shackles don't touch anything.");
else
pline("Your staff doesn't touch anything.");
return MOVE_PARTIAL;
}
else {
mon = m_at(u.ux + u.dx, u.uy + u.dy);
}
if(!mon){
if(shackles)
pline("Your broken shackles don't touch anything!");
else
pline("Your staff doesn't touch anything.");
return MOVE_PARTIAL;
}
boolean good_effect = (mon->mpeaceful && !obj->cursed) || (!mon->mpeaceful && obj->cursed);
if(good_effect){
if (!mon->mcansee) {
mon->mcansee = 1;
mon->mblinded = 0;
if (canseemon(mon)) pline("%s can see again.", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (!mon->mcanhear) {
mon->mcanhear = 1;
mon->mdeafened = 0;
if (canseemon(mon)) pline("%s can hear again.", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (mon->mconf || mon->mstun) {
mon->mconf = mon->mstun = 0;
if (canseemon(mon))
pline("%s seems steadier now.", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (mon->msleeping) {
mon->msleeping = 0;
if (canseemon(mon)) pline("%s wakes up!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (!mon->mcanmove) {
mon->mcanmove = 1;
mon->mfrozen = 0;
if (canseemon(mon)) pline("%s can move again!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (mon->mcan) {
set_mcan(mon, FALSE);
if (canseemon(mon)) pline("%s looks special again!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
}
else if(has_template(mon, PLAGUE_TEMPLATE)){
set_template(mon, 0);
mon->mhpmax = max(3, (mon->m_lev * hd_size(mon->data))-1);
if (canseemon(mon)) pline("%s has been cured!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
if(!mon->mtame && rnd(!always_hostile(mon->data) ? 12 : 20) < ACURR(A_CHA)){
pline("%s is very grateful!", Monnam(mon));
mon->mpeaceful = TRUE;
char qbuf[BUFSZ];
Sprintf(qbuf, "Turn %s away from your party?", mhim(mon));
if(yn(qbuf) != 'y'){
struct monst *newmon = tamedog_core(mon, (struct obj *)0, TRUE);
if(newmon){
mon = newmon;
newsym(mon->mx, mon->my);
}
}
}
}
else {
if (canseemon(mon)) pline("%s looks really healthy!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
}
}
//bad effect
else {
if (mon->mcanhear) {
mon->mcanhear = 0;
mon->mdeafened = d(6,6);
if (canseemon(mon)) pline("%s is stricken deaf!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (mon->mcansee) {
mon->mcansee = 0;
mon->mblinded = d(6,6);
if (canseemon(mon)) pline("%s is stricken blind!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (!mon->mstun) {
mon->mstun = 1;
if (canseemon(mon))
pline("%s wobbles!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (!mon->mconf) {
mon->mconf = 1;
if (canseemon(mon))
pline("%s seems confused!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (mon->mcanmove && !mon_resistance(mon, FREE_ACTION)) {
mon->mcanmove = 0;
mon->mfrozen = d(2,2);
if (canseemon(mon))
pline("%s seems frozen!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if(!mon->mcan){
set_mcan(mon, TRUE);
if (canseemon(mon)) pline("%s looks mediocre!", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else if (mon->mcanmove && !mon_resistance(mon, SICK_RES)) {
int dmg = d(3, 12);
if(!rn2(10))
dmg += 100;
if(m_losehp(mon, dmg, TRUE, "illness"));
else if (canseemon(mon))
pline("%s looks slightly ill.", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
} else {
if (canseemon(mon)) pline("%s looks stubbornly healthy.", Monnam(mon));
else {
if(shackles)
pline("Your broken shackles touch it!");
else
pline("Your staff touches it!");
map_invisible(u.ux+u.dx,u.uy+u.dy);
}
}
}
return MOVE_PARTIAL;
}
int
do_bloodletter(struct obj *obj)
{
if(obj->oartifact != ART_BLOODLETTER || obj != uwep){
pline("You must be wielding Bloodletter to do that.");
return MOVE_CANCELLED;
}
if (artinstance[obj->oartifact].BLactive < monstermoves){
pline("You must make an offering first.");
return MOVE_CANCELLED; // unreachable as of now
}
You("slam the bloodied morning star down, releasing it of the tainted blood in a burst.");
explode(u.ux, u.uy, AD_BLUD, 0, d(6, 6), EXPL_RED, 1);
artinstance[obj->oartifact].BLactive = 0;
return MOVE_STANDARD;
}
static int
use_rakuyo(struct obj *obj)
{
struct obj *dagger;
if(obj != uwep){
if(obj->otyp == RAKUYO) You("must wield %s to unlatch it.", the(xname(obj)));
else You("must wield %s to latch it.", the(xname(obj)));
return MOVE_CANCELLED;
}
if(obj->unpaid
|| (obj->otyp == RAKUYO_SABER && uswapwep && uswapwep->otyp == RAKUYO_DAGGER && uswapwep->unpaid)
){
You("need to buy it.");
return MOVE_CANCELLED;
}
if(obj->otyp == RAKUYO){
You("unlatch %s.",the(xname(obj)));
obj->otyp = RAKUYO_SABER;
obj->quan += 1;
dagger = splitobj(obj, 1L);
obj_extract_self(dagger);
dagger->otyp = RAKUYO_DAGGER;
fix_object(obj);
fix_object(dagger);
if (obj->oartifact && obj->oartifact == ART_BLADE_SINGER_S_SABER){
if (!art_already_exists(ART_BLADE_DANCER_S_DAGGER)){
artifact_exists(dagger, artiname(ART_BLADE_DANCER_S_DAGGER), FALSE);
dagger = oname(dagger, artiname(ART_BLADE_DANCER_S_DAGGER));
} else {
dagger->oartifact = 0;
rem_ox(dagger, OX_ENAM);
}
}
dagger = hold_another_object(dagger, "You drop %s!",
doname(dagger), (const char *)0); /*shouldn't merge, but may drop*/
if(dagger && !uswapwep && carried(dagger)){
setuswapwep(dagger);
if(!u.twoweap) dotwoweapon();
}
} else {
if(!uswapwep || uswapwep->otyp != RAKUYO_DAGGER){
You("need the matching dagger in your swap-weapon sheath or offhand.");
return MOVE_CANCELLED;
}
if(!mergable_traits(obj, uswapwep) &&
!((obj->oartifact && obj->oartifact == ART_BLADE_SINGER_S_SABER) &&
(uswapwep->oartifact && uswapwep->oartifact == ART_BLADE_DANCER_S_DAGGER))
){
pline("They don't fit together!");
return MOVE_CANCELLED;
}
if (uswapwep->oartifact && uswapwep->oartifact == ART_BLADE_DANCER_S_DAGGER){
flag_existance(ART_BLADE_DANCER_S_DAGGER, FALSE);
}
if (u.twoweap) {
u.twoweap = 0;
update_inventory();
}
useupall(uswapwep);
obj->otyp = RAKUYO;
fix_object(obj);
You("latch %s.",the(xname(obj)));
}
return MOVE_INSTANT;
}
static int
use_mercy_blade(struct obj *obj)
{
struct obj *dagger;
if(obj != uwep){
if(obj->otyp == BLADE_OF_MERCY) You("must wield %s to unlatch it.", the(xname(obj)));
else You("must wield %s to latch it.", the(xname(obj)));
return MOVE_CANCELLED;
}
if(obj->unpaid
|| (obj->otyp == BLADE_OF_MERCY && uswapwep && uswapwep->otyp == BLADE_OF_PITY && uswapwep->unpaid)
){
You("need to buy it.");
return MOVE_CANCELLED;
}
if(obj->otyp == BLADE_OF_MERCY){
You("unlatch %s.",the(xname(obj)));
obj->otyp = BLADE_OF_GRACE;
obj->quan += 1;
dagger = splitobj(obj, 1L);
obj_extract_self(dagger);
dagger->otyp = BLADE_OF_PITY;
fix_object(obj);
fix_object(dagger);
// if (obj->oartifact && obj->oartifact == ART_BLADE_SINGER_S_SABER){
// artifact_exists(dagger, artiname(ART_BLADE_DANCER_S_DAGGER), FALSE);
// dagger = oname(dagger, artiname(ART_BLADE_DANCER_S_DAGGER));
// }
dagger = hold_another_object(dagger, "You drop %s!",
doname(dagger), (const char *)0); /*shouldn't merge, but may drop*/
if(dagger && !uswapwep && carried(dagger)){
setuswapwep(dagger);
if(!u.twoweap) dotwoweapon();
}
} else {
if(!uswapwep || uswapwep->otyp != BLADE_OF_PITY){
You("need the matching dagger in your swap-weapon sheath or offhand.");
return MOVE_CANCELLED;
}
if(!mergable_traits(obj, uswapwep) &&
!((obj->oartifact && obj->oartifact == ART_BLADE_SINGER_S_SABER) &&
(uswapwep->oartifact && uswapwep->oartifact == ART_BLADE_DANCER_S_DAGGER))
){
pline("They don't fit together!");
return MOVE_CANCELLED;
}
if (u.twoweap) {
u.twoweap = 0;
update_inventory();
}
useupall(uswapwep);
obj->otyp = BLADE_OF_MERCY;
fix_object(obj);
You("latch %s.",the(xname(obj)));
}
return MOVE_INSTANT;
}
static int
use_force_blade(struct obj *obj)
{
struct obj *dagger;
if(obj != uwep){
if(obj->otyp == DOUBLE_FORCE_BLADE) You("must wield %s to unlatch it.", the(xname(obj)));
else You("must wield %s to latch it.", the(xname(obj)));
return MOVE_CANCELLED;
}
if(obj->unpaid
|| (obj->otyp == FORCE_BLADE && uswapwep && uswapwep->otyp == FORCE_BLADE && uswapwep->unpaid)
){
You("need to buy it.");
return MOVE_CANCELLED;
}
if(obj->otyp == DOUBLE_FORCE_BLADE){
You("unlatch %s.",the(xname(obj)));
obj->otyp = FORCE_BLADE;
fix_object(obj);
obj->quan += 1;
dagger = splitobj(obj, 1L);
obj_extract_self(dagger);
fix_object(obj);
dagger = hold_another_object(dagger, "You drop %s!",
doname(dagger), (const char *)0); /*shouldn't merge, but may drop*/
if(dagger && !uswapwep && carried(dagger)){
setuswapwep(dagger);
if(!u.twoweap) dotwoweapon();
}
} else {
if(!uswapwep || uswapwep->otyp != FORCE_BLADE){
You("need the matching blade in your swap-weapon sheath or offhand.");
return MOVE_CANCELLED;
}
if(!mergable_traits(obj, uswapwep)){
pline("They don't fit together!");
return MOVE_CANCELLED;
}
if (u.twoweap) {
u.twoweap = 0;
update_inventory();
}
obj->ovar1_charges = (obj->ovar1_charges + uswapwep->ovar1_charges)/2;
useupall(uswapwep);
obj->otyp = DOUBLE_FORCE_BLADE;
fix_object(obj);
You("latch %s.",the(xname(obj)));
update_inventory();
}
return MOVE_INSTANT;
}
int
use_force_sword(struct obj *obj)
{
if(obj->unpaid){
You("need to buy it.");
return MOVE_CANCELLED;
}
if(obj->otyp == FORCE_SWORD){
You("unlock %s.",the(xname(obj)));
obj->otyp = FORCE_WHIP;
} else {
You("lock %s.",the(xname(obj)));
obj->otyp = FORCE_SWORD;
}
fix_object(obj);
update_inventory();
return MOVE_INSTANT;
}
static void
use_lamp(struct obj *obj)
{
char buf[BUFSZ];
if(obj->oartifact == ART_INFINITY_S_MIRRORED_ARC){
You("can't find an %s switch", litsaber(obj) ? "off" : "on");
return;
}
if(Underwater && obj->oartifact != ART_HOLY_MOONLIGHT_SWORD && obj->otyp != POWER_ARMOR) {
pline("This is not a diving lamp.");
return;
}
if(obj->lamplit) {
if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
obj->otyp == LANTERN || obj->otyp == LANTERN_PLATE_MAIL ||
obj->otyp == DWARVISH_HELM)
pline("%s lamp is now off.", Shk_Your(buf, obj));
else if(is_lightsaber(obj)) {
if (obj->otyp == DOUBLE_LIGHTSABER || obj->oartifact == ART_ANNULUS) {
/* Do we want to activate dual bladed mode? */
if (!obj->altmode && (!obj->cursed || rn2(4))) {
You("ignite the second blade of %s.", yname(obj));
obj->altmode = TRUE;
return;
} else obj->altmode = FALSE;
}
lightsaber_deactivate(obj, TRUE);
return;
} else if(obj->otyp == POWER_ARMOR){
lightsaber_deactivate(obj,TRUE);
return;
} else
You("snuff out %s.", yname(obj));
end_burn(obj, TRUE);
return;
}
/* magic lamps with an spe == 0 (wished for) cannot be lit */
if ((!Is_candle(obj) && obj->age == 0 && obj->oartifact != ART_HOLY_MOONLIGHT_SWORD &&
!(is_lightsaber(obj) && obj->oartifact == ART_ATMA_WEAPON && !Drain_resistance))
|| (obj->otyp == MAGIC_LAMP && obj->spe == 0)
) {
if (obj->otyp == LANTERN ||
obj->otyp == LANTERN_PLATE_MAIL ||
obj->otyp == DWARVISH_HELM ||
is_lightsaber(obj) ||
obj->otyp == POWER_ARMOR
)
Your("%s has run out of power.", xname(obj));
else pline("This %s has no %s.", xname(obj), obj->otyp != GNOMISH_POINTY_HAT ? "oil" : "wax");
return;
}
if (is_gemable_lightsaber(obj) && !obj->cobj) {
pline1(nothing_happens);
return;
}
if(is_lightsaber(obj) &&
obj->cursed &&
obj->oartifact == ART_ATMA_WEAPON
){
if (!Drain_resistance) {
pline("%s for a moment, then %s brightly.",
Tobjnam(obj, "flicker"), otense(obj, "burn"));
losexp("life force drain",TRUE,TRUE,TRUE);
obj->cursed = FALSE;
}
}
if (obj->cursed && (!rn2(2) || obj->otyp == CANDLE_OF_INVOCATION) && obj->oartifact != ART_HOLY_MOONLIGHT_SWORD && obj->otyp != POWER_ARMOR && obj->otyp != ROD_OF_FORCE) {
pline("%s for a moment, then %s.",
Tobjnam(obj, "flicker"), otense(obj, "die"));
} else {
if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
obj->otyp == LANTERN || obj->otyp == LANTERN_PLATE_MAIL ||
obj->otyp == DWARVISH_HELM) {
check_unpaid(obj);
pline("%s lamp is now on.", Shk_Your(buf, obj));
} else if (is_lightsaber(obj)) {
obj->lamplit = 1; //Make yname print out the color of the lightsaber
You("ignite %s.", yname(obj));
obj->lamplit = 0;
unweapon = FALSE;
} else if (obj->otyp == POWER_ARMOR){
Your("%s powers on.",xname(obj));
} else if (obj->oartifact == ART_HOLY_MOONLIGHT_SWORD) {
int biman;
obj->lamplit = 1; //Check if the HMS will be two handed
biman = bimanual(obj,youracedata);
obj->lamplit = 0;
if(biman && uarms){
You_cant("invoke %s while wearing a shield!", yname(obj));
return;
}
You("invoke %s.", yname(obj));
if(biman && u.twoweap){
You("must now hold %s with both hands!", yname(obj));
untwoweapon();
}
unweapon = FALSE;
} else { /* candle(s) */
pline("%s flame%s %s%s",
s_suffix(Yname2(obj)),
plur(obj->quan), otense(obj, "burn"),
Blind ? "." : " brightly!");
if (obj->unpaid && costly_spot(u.ux, u.uy) &&
obj->age == 20L * (long)objects[obj->otyp].oc_cost) {
const char *ithem = obj->quan > 1L ? "them" : "it";
verbalize("You burn %s, you bought %s!", ithem, ithem);
bill_dummy_object(obj);
}
}
begin_burn(obj);
}
}
static void
light_cocktail(struct obj *obj) /* obj is a potion of oil */
{
char buf[BUFSZ];
const char *objnam =
obj->otyp == POT_OIL ? "potion" : "stick";
if (u.uswallow){
if(!is_whirly(u.ustuck->data)) {
You(no_elbow_room);
return;
} else if(!obj->lamplit){
You("can't get the %s to light. It's quite hopeless under these conditions.", objnam);
return;
}
}
if(Underwater) {
You("can't light this underwater!");
return;
}
if (obj->lamplit) {
You("snuff the lit %s.", objnam);
end_burn(obj, TRUE);
/*
* Free & add to re-merge potion. This will average the
* age of the potions. Not exactly the best solution,
* but its easy.
*/
freeinv(obj);
(void) addinv(obj);
return;
} else if (Underwater) {
There("is not enough oxygen to sustain a fire.");
return;
}
You("light %s %s.%s", shk_your(buf, obj), objnam,
Blind ? "" : " It gives off a dim light.");
if (obj->unpaid && costly_spot(u.ux, u.uy)) {
/* Normally, we shouldn't both partially and fully charge
* for an item, but (Yendorian Fuel) Taxes are inevitable...
*/
if (obj->otyp != STICK_OF_DYNAMITE) {
check_unpaid(obj);
verbalize("That's in addition to the cost of the potion, of course.");
} else {
const char *ithem = obj->quan > 1L ? "them" : "it";
verbalize("You burn %s, you bought %s!", ithem, ithem);
}
bill_dummy_object(obj);
}
makeknown(obj->otyp);
if (obj->otyp == STICK_OF_DYNAMITE) obj->yours=TRUE;
if (obj->quan > 1L) {
obj = splitobj(obj, 1L);
begin_burn(obj); /* burn before free to get position */
obj_extract_self(obj); /* free from inv */
/* shouldn't merge */
obj = hold_another_object(obj, "You drop %s!",
doname(obj), (const char *)0);
} else
begin_burn(obj);
}
static void
light_torch(struct obj *obj) /* obj is a shadowlander's torch */
{
char buf[BUFSZ];
const char *objnam = "torch";
if (u.uswallow){
if(!is_whirly(u.ustuck->data)) {
You(no_elbow_room);
return;
} else if(!obj->lamplit && obj->otyp != SUNROD && rn2(4)){
You("can't quite get the %s to light!", objnam);
return;
}
}
if(obj->lamplit && obj->otyp == SUNROD){
You("can't snuff the lit %s!", objnam);
return;
}
if(Underwater) {
You("can't light this underwater!");
return;
}
if (obj->lamplit) {
You("snuff the lit %s.", objnam);
end_burn(obj, TRUE);
/*
* Free & add to re-merge potion. This will average the
* age of the potions. Not exactly the best solution,
* but its easy.
*/
freeinv(obj);
(void) addinv(obj);
return;
} else if (Underwater) {
There("is not enough oxygen to sustain a fire.");
return;
}
if(obj->otyp == SHADOWLANDER_S_TORCH){
You("light %s %s.%s", shk_your(buf, obj), objnam,
Blind ? "" : " It gives off dark shadows.");
} else if(obj->otyp == SUNROD){
You("light %s %s.%s", shk_your(buf, obj), objnam,
Blind ? "" : " It gives off brilliant light.");
} else {
You("light %s %s.%s", shk_your(buf, obj), objnam,
Blind ? "" : " It gives off bright flickering light.");
}
if (obj->unpaid && costly_spot(u.ux, u.uy)) {
verbalize("You burn it, you bought it!");
bill_dummy_object(obj);
}
if (obj->quan > 1L) {
obj = splitobj(obj, 1L);
begin_burn(obj); /* burn before free to get position */
obj_extract_self(obj); /* free from inv */
/* shouldn't merge */
obj = hold_another_object(obj, "You drop %s!",
doname(obj), (const char *)0);
} else
begin_burn(obj);
}
static const char cuddly[] = { TOOL_CLASS, GEM_CLASS, 0 };
int
dorub(void)
{
struct obj *obj = getobj(cuddly, "rub");
if (obj && obj->oclass == GEM_CLASS) {
if (is_graystone(obj)) {
use_stone(obj);
return MOVE_STANDARD;
} else {
pline("Sorry, I don't know how to use that.");
return MOVE_CANCELLED;
}
}
if (!obj) return MOVE_CANCELLED;
if (obj->otyp == MAGIC_LAMP) {
if (obj->spe > 0 && !rn2(3)) {
if(Is_nowhere(&u.uz)){
You("hear something in there but it won't come out.");
return MOVE_CANCELLED;
}
check_unpaid_usage(obj, TRUE); /* unusual item use */
djinni_from_bottle(obj);
makeknown(MAGIC_LAMP);
obj->otyp = OIL_LAMP;
obj->spe = 0; /* for safety */
obj->age = rn1(500,1000);
if (obj->lamplit) begin_burn(obj);
update_inventory();
} else if (rn2(2) && !Blind)
You("see a puff of smoke.");
else pline1(nothing_happens);
} else if (obj->otyp == LANTERN || obj->otyp == LANTERN_PLATE_MAIL || obj->otyp == DWARVISH_HELM) {
/* message from Adventure */
pline("Rubbing the electric lamp is not particularly rewarding.");
pline("Anyway, nothing exciting happens.");
} else pline1(nothing_happens);
return MOVE_STANDARD;
}
int
dojump(void)
{
/* Physical jump */
if(!Upolyd && Role_if(PM_MONK) && uwep && (uwep->otyp == QUARTERSTAFF || uwep->otyp == KHAKKHARA) && P_SKILL(P_QUARTERSTAFF) && P_SKILL(P_MARTIAL_ARTS)){
int dist = min(P_SKILL(P_QUARTERSTAFF), P_SKILL(P_MARTIAL_ARTS));
if(dist >= P_EXPERT)
dist = P_SKILL(P_MARTIAL_ARTS);
return jump(dist);
}
return jump(0);
}
int
jump(int magic) /* 0=Physical, otherwise skill level */
{
coord cc;
if (!magic && (nolimbs(youracedata) || slithy(youracedata))) {
/* normally (nolimbs || slithy) implies !Jumping,
but that isn't necessarily the case for knights */
You_cant("jump; you have no legs!");
return MOVE_CANCELLED;
} else if (!magic && !Jumping) {
You_cant("jump very far.");
return MOVE_CANCELLED;
} else if (u.uswallow) {
if (magic) {
You("bounce around a little.");
return MOVE_STANDARD;
} else {
pline("You've got to be kidding!");
return MOVE_CANCELLED;
}
return MOVE_CANCELLED;
} else if (u.uinwater) {
if (magic) {
You("swish around a little.");
return MOVE_STANDARD;
} else {
pline("This calls for swimming, not jumping!");
return MOVE_CANCELLED;
}
return MOVE_CANCELLED;
} else if (u.ustuck) {
if (u.ustuck->mtame && !Conflict && !u.ustuck->mberserk && !u.ustuck->mconf) {
You("pull free from %s.", mon_nam(u.ustuck));
u.ustuck = 0;
return MOVE_STANDARD;
}
if (magic) {
You("writhe a little in the grasp of %s!", mon_nam(u.ustuck));
return MOVE_STANDARD;
} else {
You("cannot escape from %s!", mon_nam(u.ustuck));
return MOVE_CANCELLED;
}
return MOVE_CANCELLED;
} else if (Levitation || Weightless || Is_waterlevel(&u.uz)) {
if (magic) {
You("flail around a little.");
return MOVE_STANDARD;
} else {
You("don't have enough traction to jump.");
return MOVE_CANCELLED;
}
} else if (!magic && near_capacity() > UNENCUMBERED) {
You("are carrying too much to jump!");
return MOVE_CANCELLED;
} else if (!magic && (YouHunger <= 100*get_uhungersizemod() || ACURR(A_STR) < 6)) {
You("lack the strength to jump!");
return MOVE_CANCELLED;
} else if (Wounded_legs) {
long wl = (Wounded_legs & BOTH_SIDES);
const char *bp = body_part(LEG);
if (wl == BOTH_SIDES) bp = makeplural(bp);
if (u.usteed)
pline("%s is in no shape for jumping.", Monnam(u.usteed));
else
Your("%s%s %s in no shape for jumping.",
(wl == LEFT_SIDE) ? "left " :
(wl == RIGHT_SIDE) ? "right " : "",
bp, (wl == BOTH_SIDES) ? "are" : "is");
return MOVE_CANCELLED;
}
else if (u.usteed && u.utrap) {
pline("%s is stuck in a trap.", Monnam(u.usteed));
return MOVE_CANCELLED;
}
pline("Where do you want to jump?");
cc.x = u.ux;
cc.y = u.uy;
if (getpos(&cc, TRUE, "the desired position") < 0)
return MOVE_CANCELLED; /* user pressed ESC */
if (!magic && !(HJumping & ~INTRINSIC) && !EJumping && !(u.sealsActive&SEAL_OSE) &&
distu(cc.x, cc.y) != 5) {
/* The Knight jumping restriction still applies when riding a
* horse. After all, what shape is the knight piece in chess?
*/
pline("Illegal move!");
return MOVE_CANCELLED;
} else if (distu(cc.x, cc.y) > (magic ? 6+magic*3 : 9)) {
pline("Too far!");
return MOVE_CANCELLED;
} else if (!cansee(cc.x, cc.y)) {
You("cannot see where to land!");
return MOVE_CANCELLED;
} else if (!isok(cc.x, cc.y)) {
You("cannot jump there!");
return MOVE_CANCELLED;
} else {
coord uc;
int range, temp;
if(u.utrap)
switch(u.utraptype) {
case TT_BEARTRAP: {
long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
You("rip yourself free of the bear trap! Ouch!");
if (uarmf && uarmf->otyp == find_jboots()){
int bootdamage = d(1,10);
losehp(rnd(10), "jumping out of a bear trap", KILLED_BY);
if(!Preservation){
set_wounded_legs(side, rn1(100,50));
if(bootdamage > uarmf->spe){
claws_destroy_arm(uarmf);
}else{
for(; bootdamage >= 0; bootdamage--) drain_item(uarmf);
Your("boots are damaged!");
}
}
}
else{
losehp(d(5,6), "jumping out of a bear trap", KILLED_BY);
set_wounded_legs(side, rn1(1000,500));
}
break;
}
case TT_FLESH_HOOK: {
You("rip yourself free of the flesh hook! Ouch!");
losehp(d(13,3), "tearing free from a flesh hook", KILLED_BY);
break;
}
case TT_PIT:
You("leap from the pit!");
break;
case TT_WEB:
if(Is_lolth_level(&u.uz)){
You("cannot free yourself from the web!");
return MOVE_CANCELLED;
} else {
You("tear the web apart as you pull yourself free!");
deltrap(t_at(u.ux,u.uy));
}
break;
case TT_LAVA:
You("pull yourself above the lava!");
u.utrap = 0;
return MOVE_STANDARD;
case TT_INFLOOR:
You("strain your %s, but you're still stuck in the floor.",
makeplural(body_part(LEG)));
set_wounded_legs(LEFT_SIDE, rn1(10, 11));
set_wounded_legs(RIGHT_SIDE, rn1(10, 11));
return MOVE_STANDARD;
}
/*
* Check the path from uc to cc, calling hurtle_step at each
* location. The final position actually reached will be
* in cc.
*/
uc.x = u.ux;
uc.y = u.uy;
/* calculate max(abs(dx), abs(dy)) as the range */
range = cc.x - uc.x;
if (range < 0) range = -range;
temp = cc.y - uc.y;
if (temp < 0) temp = -temp;
if (range < temp)
range = temp;
(void) walk_path(&uc, &cc, hurtle_step, (void *)&range);
teleds(cc.x, cc.y, TRUE);
nomul(-1, "jumping around");
nomovemsg = "";
if(!Role_if(PM_MONK))
morehungry(max_ints(1, rnd(25) * get_uhungersizemod()));
return MOVE_STANDARD;
}
}
boolean
tinnable(struct obj *corpse)
{
if (corpse->otyp != CORPSE) return FALSE;
if (corpse->oeaten && !(has_blood(&mons[corpse->corpsenm]) && corpse->odrained && corpse->oeaten == drainlevel(corpse))) return FALSE;
if (!mons[corpse->corpsenm].cnutrit) return FALSE;
return TRUE;
}
static void
use_treph_crystals(register struct obj *obj)
{
struct obj *cobj = getobj(tools, "trephinate");
if(!cobj)
return;
if(cobj->otyp != CRYSTAL_SKULL){
You("examine %s in minute detail. Eventually, you conclude that it is not in fact a skull.", the(xname(cobj)));
return;
}
if(use_container(cobj, TRUE))
obj->spe--;
}
static void
use_treph_thoughts(register struct obj *obj)
{
int otyp;
struct obj *glyph;
if(Upolyd && u.uinsight < 20){
You("can't get at your own brain right now!");
return;
}
otyp = dotrephination_menu();
if(!otyp)
return;
glyph = mksobj(otyp, MKOBJ_NOINIT);
if(glyph){
remove_thought(otyp_to_thought(otyp));
//Note: affecting your true brain, so use race-if.
if(Race_if(PM_ANDROID)){
set_material_gm(glyph, PLASTIC);
fix_object(glyph);
}
if(Race_if(PM_CLOCKWORK_AUTOMATON)){
set_material_gm(glyph, COPPER);
fix_object(glyph);
}
if(Race_if(PM_WORM_THAT_WALKS)){
set_material_gm(glyph, SHELL_MAT);
fix_object(glyph);
}
hold_another_object(glyph, "You drop %s!", doname(glyph), (const char *)0);
if(ACURR(A_WIS)>ATTRMIN(A_WIS)){
adjattrib(A_WIS, -1, FALSE);
}
if(ACURR(A_INT)>ATTRMIN(A_INT)){
adjattrib(A_INT, -1, FALSE);
}
if(ACURR(A_CON)>ATTRMIN(A_CON)){
adjattrib(A_CON, -1, FALSE);
}
change_usanity(-10, FALSE);
//Note: this is always the player's HP, not their polyform HP.
u.uhp -= u.uhp/2; //Note: chopped, so 0 to 1/2 max-HP lost.
obj->spe--;
} else {
impossible("Shard creation failed in use_trephination_kit??");
}
return;
}
static void
use_trephination_kit(register struct obj *obj)
{
boolean skulls = !!carrying(CRYSTAL_SKULL);
if(!obj->spe){
pline("The kit's medical supplies are exhausted.");
return;
}
if(u.uinsight < 10 || !(u.thoughts || skulls)){
You("examine the drills in the kit, but have no idea how to use them!");
return;
}
if(skulls && u.thoughts){
int pick = dotrephination_options();
if(pick == 0){
You("close the trephination kit.");
return;
}
if(pick == TREPH_THOUGHTS){
use_treph_thoughts(obj);
return;
}
if(pick == TREPH_CRYSTALS){
use_treph_crystals(obj);
return;
}
}
else if(skulls){
use_treph_crystals(obj);
}
else {
use_treph_thoughts(obj);
}
return;
}
static void
use_tinning_kit(register struct obj *obj)
{
register struct obj *corpse, *can=0, *bld=0;
/* This takes only 1 move. If this is to be changed to take many
* moves, we've got to deal with decaying corpses...
*/
if (obj->spe <= 0) {
You("seem to be out of tins.");
return;
}
if (!(corpse = floorfood("tin", 2))) return;
if (corpse->otyp == CORPSE && corpse->oeaten && !(has_blood(&mons[corpse->corpsenm]) && corpse->odrained && corpse->oeaten == drainlevel(corpse))) {
You("cannot tin %s which is partly eaten.",something);
return;
}
if (!tinnable(corpse)) {
You_cant("tin that!");
return;
}
if (touch_petrifies(&mons[corpse->corpsenm])
&& !Stone_resistance && !uarmg) {
char kbuf[BUFSZ];
if (poly_when_stoned(youracedata))
You("tin %s without wearing gloves.",
an(mons[corpse->corpsenm].mname));
else {
pline("Tinning %s without wearing gloves is a fatal mistake...",
an(mons[corpse->corpsenm].mname));
Sprintf(kbuf, "trying to tin %s without gloves",
an(mons[corpse->corpsenm].mname));
}
instapetrify(kbuf);
}
if (is_rider(&mons[corpse->corpsenm])) {
if(Is_astralevel(&u.uz)) verbalize("Yes... But War does not preserve its enemies...");
(void) revive_corpse(corpse, REVIVE_MONSTER);
return;
}
if (mons[corpse->corpsenm].cnutrit == 0) {
pline("That's too insubstantial to tin.");
return;
}
consume_obj_charge(obj, TRUE);
if((has_blood(&mons[corpse->corpsenm]) && !corpse->odrained)
|| !(Race_if(PM_VAMPIRE) || Race_if(PM_INCANTIFIER) || Race_if(PM_ETHEREALOID) ||
umechanoid)
|| yn("This corpse does not have blood. Tin it?") == 'y'
){
if ((can = mksobj(TIN, MKOBJ_NOINIT)) != 0) {
static const char you_buy_it[] = "You tin it, you bought it!";
can->corpsenm = corpse->corpsenm;
can->cursed = obj->cursed;
can->blessed = obj->blessed;
can->owt = weight(can);
can->known = 1;
can->spe = -1; /* Mark tinned tins. No spinach allowed... */
if(has_blood(&mons[corpse->corpsenm]) && !corpse->odrained){
if ((bld = mksobj(POT_BLOOD, MKOBJ_NOINIT)) != 0) {
bld->corpsenm = corpse->corpsenm;
bld->cursed = obj->cursed;
bld->blessed = obj->blessed;
bld->known = 1;
}
}
if (carried(corpse)) {
if (corpse->unpaid)
verbalize(you_buy_it);
useup(corpse);
} else {
if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge)
verbalize(you_buy_it);
useupf(corpse, 1L);
}
can = hold_another_object(can, "You make, but cannot pick up, %s.",
doname(can), (const char *)0);
if(bld) bld = hold_another_object(bld, "You make, but cannot pick up, %s.",
doname(bld), (const char *)0);
} else impossible("Tinning failed.");
}
}
void
use_unicorn_horn(struct obj *obj)
{
#define PROP_COUNT 6 /* number of properties we're dealing with */
#define ATTR_COUNT (A_MAX*3) /* number of attribute points we might fix */
int idx, val, val_limit,
trouble_count, unfixable_trbl, did_prop, did_attr;
int trouble_list[PROP_COUNT + ATTR_COUNT];
if (obj && obj->cursed) {
long lcount = (long) rnd(100);
switch (rn2(5)) {
case 0: make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON),20),
xname(obj), TRUE, SICK_NONVOMITABLE);
break;
case 1: make_blinded(Blinded + lcount, TRUE);
break;
case 2: if (!Confusion)
You("suddenly feel %s.",
Hallucination ? "trippy" : "confused");
make_confused(HConfusion + lcount, TRUE);
break;
case 3: make_stunned(HStun + lcount, TRUE);
break;
// case 4: (void) adjattrib(rn2(A_MAX), -1, FALSE);
// break;
case 4: (void) make_hallucinated(HHallucination + lcount, TRUE, 0L);
break;
}
return;
}
/*
* Entries in the trouble list use a very simple encoding scheme.
*/
#define prop2trbl(X) ((X) + A_MAX)
#define attr2trbl(Y) (Y)
#define prop_trouble(X) trouble_list[trouble_count++] = prop2trbl(X)
#define attr_trouble(Y) trouble_list[trouble_count++] = attr2trbl(Y)
trouble_count = unfixable_trbl = did_prop = did_attr = 0;
/* collect property troubles */
if (Sick) prop_trouble(SICK);
if (Blinded > (long)u.ucreamed) prop_trouble(BLINDED);
if (HHallucination) prop_trouble(HALLUC);
if (Vomiting) prop_trouble(VOMITING);
if (HConfusion) prop_trouble(CONFUSION);
if (HStun) prop_trouble(STUNNED);
unfixable_trbl = unfixable_trouble_count(TRUE);
// /* collect attribute troubles */
// for (idx = 0; idx < A_MAX; idx++) {
// val_limit = AMAX(idx);
// /* don't recover strength lost from hunger */
// if (idx == A_STR && u.uhs >= WEAK) val_limit--;
// /* don't recover more than 3 points worth of any attribute */
// if (val_limit > ABASE(idx) + 3) val_limit = ABASE(idx) + 3;
// for (val = ABASE(idx); val < val_limit; val++)
// attr_trouble(idx);
// /* keep track of unfixed trouble, for message adjustment below */
// unfixable_trbl += (AMAX(idx) - val_limit);
// }
if (trouble_count == 0) {
pline1(nothing_happens);
return;
} else if (trouble_count > 1) { /* shuffle */
int i, j, k;
for (i = trouble_count - 1; i > 0; i--)
if ((j = rn2(i + 1)) != i) {
k = trouble_list[j];
trouble_list[j] = trouble_list[i];
trouble_list[i] = k;
}
}
/*
* Chances for number of troubles to be fixed
* 0 1 2 3 4 5 6 7
* blessed: 22.7% 22.7% 19.5% 15.4% 10.7% 5.7% 2.6% 0.8%
* uncursed: 35.4% 35.4% 22.9% 6.3% 0 0 0 0
*/
val_limit = rn2( d(2, (obj && obj->blessed) ? 4 : 2) );
if (val_limit > trouble_count) val_limit = trouble_count;
/* fix [some of] the troubles */
for (val = 0; val < val_limit; val++) {
idx = trouble_list[val];
switch (idx) {
case prop2trbl(SICK):
make_sick(0L, (char *) 0, TRUE, SICK_ALL);
did_prop++;
break;
case prop2trbl(BLINDED):
make_blinded((long)u.ucreamed, TRUE);
did_prop++;
break;
case prop2trbl(HALLUC):
(void) make_hallucinated(0L, TRUE, 0L);
did_prop++;
break;
case prop2trbl(VOMITING):
make_vomiting(0L, TRUE);
did_prop++;
break;
case prop2trbl(CONFUSION):
make_confused(0L, TRUE);
did_prop++;
break;
case prop2trbl(STUNNED):
make_stunned(0L, TRUE);
did_prop++;
break;
default:
if (idx >= 0 && idx < A_MAX) {
ABASE(idx) += 1;
did_attr++;
} else
panic("use_unicorn_horn: bad trouble? (%d)", idx);
break;
}
}
if (did_attr)
pline("This makes you feel %s!",
(did_prop + did_attr) == (trouble_count + unfixable_trbl) ?
"great" : "better");
else if (!did_prop)
pline("Nothing seems to happen.");
flags.botl = (did_attr || did_prop);
#undef PROP_COUNT
#undef ATTR_COUNT
#undef prop2trbl
#undef attr2trbl
#undef prop_trouble
#undef attr_trouble
}
/*
* Timer callback routine: turn figurine into monster
*/
void
fig_transform(void * arg, long timeout)
{
struct obj *figurine = (struct obj *)arg;
struct monst *mtmp;
coord cc;
boolean cansee_spot, silent, okay_spot;
boolean redraw = FALSE;
char monnambuf[BUFSZ], carriedby[BUFSZ];
if (!figurine) {
#ifdef DEBUG
pline("null figurine in fig_transform()");
#endif
return;
}
silent = (timeout != monstermoves); /* happened while away */
okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0);
if (figurine->where == OBJ_INVENT ||
figurine->where == OBJ_MINVENT)
okay_spot = enexto(&cc, cc.x, cc.y,
&mons[figurine->corpsenm]);
if (!okay_spot ||
!figurine_location_checks(figurine,&cc, TRUE)) {
/* reset the timer to try again later */
(void) start_timer((long)rnd(5000), TIMER_OBJECT,
FIG_TRANSFORM, (void *)figurine);
return;
}
cansee_spot = cansee(cc.x, cc.y);
mtmp = make_familiar(figurine, cc.x, cc.y, TRUE);
if (mtmp) {
Sprintf(monnambuf, "%s",an(m_monnam(mtmp)));
switch (figurine->where) {
case OBJ_INVENT:
if (Blind)
You_feel("%s %s from your pack!", something,
locomotion(mtmp,"drop"));
else
You("see %s %s out of your pack!",
monnambuf,
locomotion(mtmp,"drop"));
break;
case OBJ_FLOOR:
if (cansee_spot && !silent) {
You("suddenly see a figurine transform into %s!",
monnambuf);
redraw = TRUE; /* update figurine's map location */
}
break;
case OBJ_MINVENT:
if (cansee_spot && !silent) {
struct monst *mon;
mon = figurine->ocarry;
/* figurine carring monster might be invisible */
if (canseemon(figurine->ocarry)) {
Sprintf(carriedby, "%s pack",
s_suffix(a_monnam(mon)));
}
else if (is_pool(mon->mx, mon->my, FALSE))
Strcpy(carriedby, "empty water");
else
Strcpy(carriedby, "thin air");
You("see %s %s out of %s!", monnambuf,
locomotion(mtmp, "drop"), carriedby);
}
break;
#if 0
case OBJ_MIGRATING:
break;
#endif
default:
impossible("figurine came to life where? (%d)",
(int)figurine->where);
break;
}
}
/* free figurine now */
obj_extract_self(figurine);
obfree(figurine, (struct obj *)0);
if (redraw) newsym(cc.x, cc.y);
}
static boolean
figurine_location_checks(struct obj *obj, coord *cc, boolean quietly)
{
xchar x,y;
if (carried(obj) && u.uswallow) {
if (!quietly)
You("don't have enough room in here.");
return FALSE;
}
x = cc->x; y = cc->y;
if (!isok(x,y)) {
if (!quietly)
You("cannot put the figurine there.");
return FALSE;
}
if (IS_ROCK(levl[x][y].typ) &&
!(species_passes_walls(&mons[obj->corpsenm]) && may_passwall(x,y))) {
if (!quietly)
You("cannot place a figurine in %s!",
IS_TREES(levl[x][y].typ) ? "a tree" : "solid rock");
return FALSE;
}
if (boulder_at(x,y) && !species_passes_walls(&mons[obj->corpsenm])
&& !throws_rocks(&mons[obj->corpsenm])) {
if (!quietly)
You("cannot fit the figurine on the %s.",xname(boulder_at(x,y)));
return FALSE;
}
return TRUE;
}
static int
use_figurine(struct obj **optr)
{
register struct obj *obj = *optr;
xchar x, y;
coord cc;
if (u.uswallow) {
/* can't activate a figurine while swallowed */
if (!figurine_location_checks(obj, (coord *)0, FALSE))
return MOVE_CANCELLED;
}
if(!getdir((char *)0)) {
return MOVE_CANCELLED;
}
x = u.ux + u.dx; y = u.uy + u.dy;
cc.x = x; cc.y = y;
/* Passing FALSE arg here will result in messages displayed */
if (!figurine_location_checks(obj, &cc, FALSE))
return MOVE_CANCELLED;
You("%s and it transforms.",
(u.dx||u.dy) ? "set the figurine beside you" :
(Weightless || Is_waterlevel(&u.uz) ||
is_pool(cc.x, cc.y, TRUE)) ?
"release the figurine" :
(u.dz < 0 ?
"toss the figurine into the air" :
"set the figurine on the ground"));
(void) make_familiar(obj, cc.x, cc.y, FALSE);
(void) stop_timer(FIG_TRANSFORM, obj->timed);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
}
static void
vape(struct obj *obj)
{
struct obj *otmp;
if(breathless(youracedata)){
You("don't have a proper respiratory system!");
return;
}
if(obj->spe < 1){
pline("The %s is out of juice!",xname(obj));
return;
}
You("%s the %s.",Hallucination?"smack":"inhale from",xname(obj));
otmp = mksobj(obj->ovar1,MKOBJ_NOINIT);
otmp->cursed = obj->cursed;
otmp->blessed = obj->blessed;
potionbreathe(otmp);
if(obj->ovar1 == POT_WATER || obj->ovar1 == POT_OIL || obj->ovar1 == POT_FRUIT_JUICE){
You("rip a fat cloud.");
makemon(&mons[PM_FOG_CLOUD], u.ux, u.uy, MM_ADJACENTOK);
}
obfree(otmp, (struct obj*)0);
obj->known = 1;
obj->spe--;
}
static int
use_crystal_skull(struct obj **optr)
{
coord cc;
xchar x, y;
if(u.veil || !(Unblind_telepat || (Blind_telepat && Blind))){
pline("It's just a clear glass skull.");
return MOVE_CANCELLED;
}
if(!get_ox(*optr, OX_EMON)){
pline("It's REALLY just a glass skull.");
return MOVE_CANCELLED;
}
if(!getdir((char *)0)) {
flags.move = multi = 0;
return MOVE_CANCELLED;
}
x = u.ux + u.dx; y = u.uy + u.dy;
if(!enexto(&cc, x, y, (struct permonst *)0)){
pline("No room!");
return MOVE_CANCELLED;
}
//Note: summoning from summoned crystal skulls doesn't work well
if(get_ox(*optr, OX_ESUM) || obj_summon_out(*optr)){
pline("The imprisoned mind is dreaming.");
return MOVE_STANDARD;
}
if((*optr)->age > monstermoves){
pline("The imprisoned mind is exhausted.");
change_usanity(save_vs_sanloss() ? 0 : -1, FALSE);
return MOVE_STANDARD;
}
if(rnd(20) > u.uinsight || u.uen < EMON(*optr)->m_lev){
You_cant("maintain your focus on the crystal!");
if(save_vs_sanloss())
change_usanity(-1, FALSE);
else
change_usanity(-1*rnd(10), TRUE);
return MOVE_STANDARD;
}
You("awaken the imprisoned mind!");
u.uen -= EMON(*optr)->m_lev;
flags.botl = 1;
if(save_vs_sanloss())
change_usanity(-1*rnd(8), TRUE);
else
change_usanity(-1*d(2,6), TRUE);
x_uses_crystal_skull(optr, &youmonst, &cc);
return MOVE_STANDARD;
}
void
x_uses_crystal_skull(struct obj **optr, struct monst *master, coord *cc)
{
struct obj *obj = *optr;
struct obj *oinv, *otmp;
struct monst *mtmp;
mtmp = montraits(obj, cc);
if(mtmp){
obj->age = monstermoves + 250L + rn2(250L);
/* if skull has been named, give same name to the monster */
if (get_ox(obj, OX_ENAM))
mtmp = christen_monst(mtmp, ONAME(obj));
mtmp->movement = NORMAL_SPEED;
add_mx(mtmp, MX_ESUM);
start_timer(ESUMMON_PERMANENT, TIMER_MONSTER, DESUMMON_MON, (void *)mtmp);
for(oinv = obj->cobj; oinv; oinv = oinv->nobj){
//Invalid items that are in the skull (possibly as a result of special cases) are skipped and handled later.
if(oinv->otyp == TREPHINATION_KIT || ensouled_item(oinv))
continue;
otmp = duplicate_obj(oinv);
obj_extract_self(otmp);
if(otmp->oclass == SCROLL_CLASS){
otmp = poly_obj(otmp, SCR_BLANK_PAPER);
}
if(otmp->oclass == SPBOOK_CLASS){
otmp = poly_obj(otmp, SPE_BLANK_PAPER);
}
if(!is_ammo(otmp)){
if(otmp->quan > 3)
otmp->quan = rnd(3);
fix_object(otmp);
}
if(otmp->otyp == MAGIC_MARKER){
otmp->recharged = max(1, otmp->recharged);
otmp->spe = 0;
}
//If the item was not merged, check if anything special should be done with it (like equipping a saddle)
if(!mpickobj(mtmp,otmp)){
if(otmp->otyp == SADDLE && !(mtmp->misc_worn_check&W_SADDLE) && can_saddle(mtmp, otmp)){
mtmp->misc_worn_check |= W_SADDLE;
otmp->owornmask = W_SADDLE;
otmp->leashmon = mtmp->m_id;
update_mon_intrinsics(mtmp, otmp, TRUE, FALSE);
}
}
}
m_level_up_intrinsic(mtmp);
if(master == &youmonst || master->mtame){
mtmp = tamedog_core(mtmp, (struct obj *)0, TRUE);
if(mtmp && get_mx(mtmp, MX_EDOG)){
EDOG(mtmp)->dominated = TRUE;
EDOG(mtmp)->hungrytime = monstermoves + 4500;
}
}
else {
if(master->mfaction)
set_faction(mtmp, master->mfaction);
mtmp->mpeaceful = master->mpeaceful;
}
mark_mon_as_summoned(mtmp, master, ESUMMON_PERMANENT, 0);
mtmp->mextra_p->esum_p->sm_o_id = obj->o_id;
//After being marked as summoned, extract invalid items from skull and add to inventory.
// These objects are "really there"/will remain after the monster is defeated.
for(oinv = obj->cobj; oinv; oinv = oinv->nobj){
if(oinv->otyp == TREPHINATION_KIT || ensouled_item(oinv)){
obj_extract_self(oinv);
mpickobj(mtmp,oinv);
}
}
m_dowear(mtmp, TRUE);
init_mon_wield_item(mtmp);
}
}
static const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 };
static const char need_to_remove_outer_armor[] =
"need to remove your %s to grease your %s.";
static void
use_grease(struct obj *obj)
{
struct obj *otmp;
char buf[BUFSZ];
if (Glib) {
pline("%s from your %s.", Tobjnam(obj, "slip"),
makeplural(body_part(FINGER)));
dropx(obj);
return;
}
if (obj->spe > 0) {
if ((obj->cursed || Fumbling) && !rn2(2)) {
consume_obj_charge(obj, TRUE);
pline("%s from your %s.", Tobjnam(obj, "slip"),
makeplural(body_part(FINGER)));
dropx(obj);
return;
}
otmp = getobj(lubricables, "grease");
if (!otmp) return;
if ((otmp->owornmask & WORN_ARMOR) && uarmc) {
Strcpy(buf, xname(uarmc));
You(need_to_remove_outer_armor, buf, xname(otmp));
return;
}
if ((otmp->owornmask & WORN_SHIRT) && (uarmc || (uarm && arm_blocks_upper_body(uarm->otyp)))) {
Strcpy(buf, uarmc ? xname(uarmc) : "");
if (uarmc && uarm) Strcat(buf, " and ");
Strcat(buf, uarm ? xname(uarm) : "");
You(need_to_remove_outer_armor, buf, xname(otmp));
return;
}
consume_obj_charge(obj, TRUE);
if (otmp != &zeroobj) {
You("cover %s with a thick layer of grease.",
yname(otmp));
otmp->greased = 1;
if (obj->cursed && !nohands(youracedata)) {
incr_itimeout(&Glib, rnd(15));
pline("Some of the grease gets all over your %s.",
makeplural(body_part(HAND)));
}
} else {
Glib += rnd(15);
You("coat your %s with grease.",
makeplural(body_part(FINGER)));
}
} else {
if (obj->known)
pline("%s empty.", Tobjnam(obj, "are"));
else
pline("%s to be empty.", Tobjnam(obj, "seem"));
}
update_inventory();
}
static struct trapinfo {
struct obj *tobj;
xchar tx, ty;
int time_needed;
boolean force_bungle;
} trapinfo;
void
reset_trapset(void)
{
trapinfo.tobj = 0;
trapinfo.force_bungle = 0;
}
/* touchstones - by Ken Arnold */
static void
use_stone(struct obj *tstone)
{
struct obj *obj;
boolean do_scratch;
const char *streak_color, *choices;
char stonebuf[QBUFSZ];
static const char scritch[] = "\"scritch, scritch\"";
static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 };
static const char justgems[3] = { ALLOW_NONE, GEM_CLASS, 0 };
#ifndef GOLDOBJ
struct obj goldobj;
#endif
/* in case it was acquired while blinded */
if (!Blind) tstone->dknown = 1;
/* when the touchstone is fully known, don't bother listing extra
junk as likely candidates for rubbing */
choices = (tstone->otyp == TOUCHSTONE && tstone->dknown &&
objects[TOUCHSTONE].oc_name_known)||tstone->otyp == ROCK ? justgems : allowall;
Sprintf(stonebuf, tstone->otyp == ROCK ? "beat with the stone%s":"rub on the stone%s", plur(tstone->quan));
if ((obj = getobj(choices, stonebuf)) == 0)
return;
#ifndef GOLDOBJ
if (obj->oclass == COIN_CLASS) {
u.ugold += obj->quan; /* keep botl up to date */
goldobj = *obj;
dealloc_obj(obj);
obj = &goldobj;
}
#endif
if (obj == tstone && obj->quan == 1) {
You_cant("%s %s %s itself.",obj->otyp == ROCK ? "beat":"rub" ,obj->otyp == ROCK ? "with":"on",the(xname(obj)));
return;
}
if (tstone->otyp == TOUCHSTONE && tstone->cursed &&
obj->oclass == GEM_CLASS && !is_graystone(obj) &&
!obj_resists(obj, 0, 100)) {
if (Blind)
pline("You feel something shatter.");
else if (Hallucination)
pline("Oh, wow, look at the pretty shards.");
else
pline("A sharp crack shatters %s%s.",
(obj->quan > 1) ? "one of " : "", the(xname(obj)));
#ifndef GOLDOBJ
/* assert(obj != &goldobj); */
#endif
useup(obj);
return;
}
if (Blind) {
pline("%s", scritch);
return;
} else if (Hallucination) {
pline("Oh wow, man: Fractals!");
return;
}
do_scratch = FALSE;
streak_color = 0;
switch (obj->oclass) {
case GEM_CLASS: /* these have class-specific handling below */
case RING_CLASS:
if (tstone->otyp != TOUCHSTONE && tstone->otyp != ROCK) {
do_scratch = TRUE;
} else if (obj->oclass == GEM_CLASS && tstone->otyp == TOUCHSTONE &&(tstone->blessed ||
(!tstone->cursed &&
(Role_if(PM_ARCHEOLOGIST) || Race_if(PM_GNOME))))) {
makeknown(TOUCHSTONE);
makeknown(obj->otyp);
prinv((char *)0, obj, 0L);
return;
} else if(obj->oclass == GEM_CLASS && tstone->otyp == ROCK){
if(obj->otyp == ROCK || objects[obj->otyp].oc_tough || obj->oartifact){
pline("It's too hard to break!");
return;
}
if(obj->otyp == LOADSTONE && obj->cursed){
Your("rock sticks to the loadstone!");/*How iron-ic*/
return;
}
if(obj->oknapped){
pline("%s is already knapped!",The(xname(obj)));
return;
}
if(obj->quan > 1){
obj = splitobj(obj,1L);
}
if(Role_if(PM_CAVEMAN) || u.utats & TAT_SPEARHEAD){
You("knap the %s into a point!",xname(obj));
obj->oknapped = KNAPPED_SPEAR;
if(obj->otyp == LOADSTONE) obj->owt /= 10;
obj_extract_self(obj); /* free from inv */
if(obj->otyp == LOADSTONE) obj->cursed = 0;
obj = hold_another_object(obj, "You drop %s!",
doname(obj), (const char *)0);
} else {
You("break the %s into many pieces!",xname(obj));
obj_extract_self(obj); /* free from inv */
obfree(obj,(struct obj *) 0);
}
return;
} else {
/* either a ring or the touchstone was not effective */
if (obj->obj_material == GLASS) {
do_scratch = TRUE;
break;
}
}
streak_color = c_obj_colors[obj->obj_color];
break; /* gem or ring */
default:
switch (obj->obj_material) {
case CLOTH:
pline("%s a little more polished now.", Tobjnam(tstone, "look"));
return;
case LIQUID:
if (!obj->known) /* note: not "whetstone" */
You("must think this is a wetstone, do you?");
else
pline("%s a little wetter now.", Tobjnam(tstone, "are"));
return;
case WAX:
streak_color = "waxy";
break; /* okay even if not touchstone */
case WOOD:
streak_color = "wooden";
break; /* okay even if not touchstone */
case GOLD:
do_scratch = TRUE; /* scratching and streaks */
streak_color = "golden";
break;
case SILVER:
do_scratch = TRUE; /* scratching and streaks */
streak_color = "silvery";
break;
case GEMSTONE:
if (obj->sub_material) {
/* similare check as above */
if (tstone->otyp != TOUCHSTONE) {
do_scratch = TRUE;
}
else if (tstone->blessed || (!tstone->cursed &&
(Role_if(PM_ARCHEOLOGIST) || Race_if(PM_GNOME)))) {
makeknown(TOUCHSTONE);
makeknown(obj->sub_material);
prinv((char *)0, obj, 0L);
return;
}
/* the touchstone was not effective */
streak_color = c_obj_colors[obj->obj_color];
}
else {
do_scratch = (tstone->otyp != TOUCHSTONE);
}
break;
default:
/* Objects passing the is_flimsy() test will not
scratch a stone. They will leave streaks on
non-touchstones and touchstones alike. */
if (is_flimsy(obj))
streak_color = c_obj_colors[obj->obj_color];
else
do_scratch = (tstone->otyp != TOUCHSTONE);
break;
}
break; /* default oclass */
}
Sprintf(stonebuf, "stone%s", plur(tstone->quan));
if (do_scratch)
pline("You make %s%sscratch marks on the %s.",
streak_color ? streak_color : (const char *)"",
streak_color ? " " : "", stonebuf);
else if (streak_color)
pline("You see %s streaks on the %s.", streak_color, stonebuf);
else
pline("%s", scritch);
return;
}
static int
use_sensor(struct obj *sensor)
{
int scantype = 0;
if(sensor->spe <= 0){
pline("It seems inert.");
return MOVE_CANCELLED;
} else {
scantype = sensorMenu();
if(!scantype) return MOVE_CANCELLED;
switch(scantype){
case POT_MONSTER_DETECTION:
monster_detect(sensor, 0);
break;
case POT_OBJECT_DETECTION:
object_detect(sensor, 0);
break;
case SPE_CLAIRVOYANCE:
do_vicinity_map(u.ux,u.uy);
break;
case WAN_PROBING:{
struct obj *pobj;
if (!getdir((char *)0)) return MOVE_CANCELLED;
if (!isok(u.ux+u.dx,u.uy+u.dy)) return MOVE_CANCELLED;
if (u.dz < 0) {
You("scan the %s thoroughly. It seems it is %s.", ceiling(u.ux,u.uy), an(ceiling(u.ux,u.uy)));
} else if(u.dz > 0) {
pobj = level.objects[u.ux][u.uy];
for(; pobj; pobj = pobj->nexthere){
/* target object has now been "seen (up close)" */
pobj->dknown = 1;
if (Is_container(pobj) || pobj->otyp == STATUE || (pobj->otyp == CRYSTAL_SKULL && u.uinsight >= 20)) {
if (!pobj->cobj)
pline("%s empty.", Tobjnam(pobj, "are"));
else {
struct obj *o;
/* view contents (not recursively) */
for (o = pobj->cobj; o; o = o->nobj)
o->dknown = 1; /* "seen", even if blind */
(void) display_cinventory(pobj);
}
}
}
You("probe beneath the %s.", surface(u.ux,u.uy));
display_binventory(u.ux, u.uy, TRUE);
} else {
struct monst *mat = m_at(u.ux+u.dx,u.uy+u.dy);
if(mat) probe_monster(mat);
pobj = level.objects[u.ux+u.dx][u.uy+u.dy];
for(; pobj; pobj = pobj->nexthere){
/* target object has now been "seen (up close)" */
pobj->dknown = 1;
if (Is_container(pobj) || pobj->otyp == STATUE || (pobj->otyp == CRYSTAL_SKULL && u.uinsight >= 20)) {
if (!pobj->cobj)
pline("%s empty.", Tobjnam(pobj, "are"));
else {
struct obj *o;
/* view contents (not recursively) */
for (o = pobj->cobj; o; o = o->nobj)
o->dknown = 1; /* "seen", even if blind */
(void) display_cinventory(pobj);
}
}
}
}
} break;
case WAN_SECRET_DOOR_DETECTION:
findit();
break;
}
}
sensor->spe--;
return MOVE_STANDARD;
}
static int
sensorMenu(void)
{
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet;
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Functions");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
incntlet = 'c';
Sprintf(buf, "Scan for creatures");
any.a_int = POT_MONSTER_DETECTION; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = 'd';
Sprintf(buf, "Scan for secret doors");
any.a_int = WAN_SECRET_DOOR_DETECTION; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = 'o';
Sprintf(buf, "Scan for objects");
any.a_int = POT_OBJECT_DETECTION; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = 'p';
Sprintf(buf, "Focused probe");
any.a_int = WAN_PROBING; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = 't';
Sprintf(buf, "Survey terrain");
any.a_int = SPE_CLAIRVOYANCE; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
end_menu(tmpwin, "Choose function:");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n > 0){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
static int
use_hypospray(struct obj *hypo)
{
struct obj *amp = getobj(tools, "inject");
int i, ii, nothing=0;
if(!amp) return MOVE_CANCELLED;
if(amp->otyp != HYPOSPRAY_AMPULE){
You("can't inject that!");
return MOVE_CANCELLED;
}
if (!getdir((char *)0)) return MOVE_CANCELLED;
if(u.dz < 0){
You("don't see a patient up there.");
return MOVE_CANCELLED;
} else if(u.dz > 0){
You("doubt the floor will respond to drugs.");
return MOVE_CANCELLED;
} else if(u.dx || u.dy){
struct monst *mtarg = m_at(u.ux+u.dx,u.uy+u.dy);
if(!mtarg){
You("don't find a patient there.");
return MOVE_STANDARD;
}
if(amp->spe <= 0){
pline("The ampule is empty!");
return MOVE_STANDARD;
}
if(!has_blood_mon(mtarg)){
pline("It would seem that the patient has no circulatory system....");
} else switch(amp->ovar1_ampule){
case POT_HEALING:
if (mtarg->mtyp == PM_PESTILENCE){
mtarg->mhp -= d(6 + 2 * bcsign(amp), 4);
if(mtarg->mhp <= 0) xkilled(mtarg,1);
break;
}
if(mtarg->mhp < mtarg->mhpmax) {
mtarg->mhp = min_ints(mtarg->mhpmax,mtarg->mhp+d(6 + 2 * bcsign(amp), 4));
if (canseemon(mtarg))
pline("%s looks better.", Monnam(mtarg));
}
break;
case POT_EXTRA_HEALING:
if (mtarg->mtyp == PM_PESTILENCE){
mtarg->mhp -= d(6 + 2 * bcsign(amp), 8);
if(mtarg->mhp <= 0) xkilled(mtarg,1);
break;
}
if(mtarg->mhp < mtarg->mhpmax) {
mtarg->mhp = min_ints(mtarg->mhpmax,mtarg->mhp+d(6 + 2 * bcsign(amp), 8));
if (canseemon(mtarg))
pline("%s looks much better.", Monnam(mtarg));
}
break;
case POT_FULL_HEALING:
if (mtarg->mtyp == PM_PESTILENCE){
if((mtarg->mhpmax > 3) && !resist(mtarg, POTION_CLASS, 0, NOTELL))
mtarg->mhpmax /= 2;
if((mtarg->mhp > 2) && !resist(mtarg, POTION_CLASS, 0, NOTELL))
mtarg->mhp /= 2;
if (mtarg->mhp > mtarg->mhpmax) mtarg->mhp = mtarg->mhpmax;
if(mtarg->mhp <= 0) xkilled(mtarg,1);
if (canseemon(mtarg))
pline("%s looks rather ill.", Monnam(mtarg));
break;
}
case POT_GAIN_ABILITY:
case POT_RESTORE_ABILITY:
if(mtarg->mhp < mtarg->mhpmax) {
mtarg->mhp = min(mtarg->mhpmax,mtarg->mhp+400);
if (canseemon(mtarg))
pline("%s looks sound and hale again.", Monnam(mtarg));
}
break;
case POT_BLINDNESS:
if(!resists_blnd(mtarg)) {
register int btmp = rn1(200, 250 - 125 * bcsign(amp));
btmp += mtarg->mblinded;
mtarg->mblinded = min(btmp,127);
mtarg->mcansee = 0;
}
break;
case POT_HALLUCINATION:
if(!resist(mtarg, POTION_CLASS, 0, NOTELL) &&
!mon_resistance(mtarg, HALLUC_RES)) {
mtarg->mconf = TRUE;
mtarg->mberserk = TRUE;
}
case POT_CONFUSION:
if(!resist(mtarg, POTION_CLASS, 0, NOTELL))
mtarg->mconf = TRUE;
break;
case POT_PARALYSIS:
if (mtarg->mcanmove) {
if (mon_resistance(mtarg, FREE_ACTION)) {
pline("%s stiffens momentarily.", Monnam(mtarg));
} else {
mtarg->mcanmove = 0;
mtarg->mfrozen = rn1(10, 25 - 12*bcsign(amp));
}
}
break;
case POT_SPEED:
mon_adjust_speed(mtarg, 1, amp, TRUE);
break;
case POT_GAIN_ENERGY:
if(amp->cursed){
if (canseemon(mtarg))
pline("%s looks lackluster.", Monnam(mtarg));
set_mcan(mtarg, TRUE);
} else {
if (canseemon(mtarg))
pline("%s looks full of energy.", Monnam(mtarg));
mtarg->mspec_used = 0;
set_mcan(mtarg, FALSE);
}
break;
case POT_SLEEPING:
if (sleep_monst(mtarg, rn1(10, 25 - 12*bcsign(amp)), POTION_CLASS)) {
pline("%s falls asleep.", Monnam(mtarg));
slept_monst(mtarg);
}
break;
case POT_POLYMORPH:
if (canseemon(mtarg)) pline("%s suddenly mutates!", Monnam(mtarg));
if(!resists_poly(mtarg->data))
newcham(mtarg, NON_PM, FALSE, FALSE);
break;
case POT_AMNESIA:
if(!amp->cursed){
if (canseemon(mtarg))
pline("%s looks more tranquil.", Monnam(mtarg));
if(!amp->blessed){
untame(mtarg, 1);
mtarg->mferal = 0;
}
mtarg->mcrazed = 0;
mtarg->mdisrobe = 0;
mtarg->mberserk = 0;
mtarg->mdoubt = 0;
} else {
if (canseemon(mtarg))
pline("%s looks angry and confused!", Monnam(mtarg));
untame(mtarg, 0);
mtarg->mcrazed = 1;
mtarg->mberserk = 1;
mtarg->mconf = 1;
mtarg->mferal = 0;
}
break;
}
} else {
if(amp->spe <= 0){
pline("The ampule is empty!");
return MOVE_STANDARD;
}
switch(amp->ovar1_ampule){
case POT_GAIN_ABILITY:
if(amp->cursed) {
//poison
} else if (Fixed_abil) {
nothing++;
} else { /* If blessed, increase all; if not, try up to */
int itmp; /* 6 times to find one which can be increased. */
i = -1; /* increment to 0 */
for (ii = A_MAX; ii > 0; ii--) {
i = (amp->blessed ? i + 1 : rn2(A_MAX));
/* only give "your X is already as high as it can get"
message on last attempt (except blessed potions) */
itmp = (amp->blessed || ii == 1) ? 0 : -1;
if (adjattrib(i, 1, itmp) && !amp->blessed)
break;
}
}
break;
case POT_RESTORE_ABILITY:
if (amp->blessed && u.ulevel < u.ulevelmax) {
pluslvl(FALSE);
}
if(amp->blessed && u.umorgul>0){
u.umorgul--;
if(u.umorgul)
You_feel("the chill of death lessen.");
else
You_feel("the chill of death fade away.");
}
if(amp->blessed && u.umummyrot){
u.umummyrot = 0;
You("stop shedding dust.");
}
if(!amp->cursed){
//Restore sanity if blessed or uncursed
if(amp->blessed)
change_usanity(20, FALSE);
else
change_usanity(5, FALSE);
}
if(amp->cursed) {
pline("Ulch! This makes you feel mediocre!");
break;
} else {
int lim;
pline("Wow! This makes you feel %s!",
(amp->blessed) ?
(unfixable_trouble_count(FALSE) ? "better" : "great")
: "good");
i = rn2(A_MAX); /* start at a random point */
for (ii = 0; ii < A_MAX; ii++) {
lim = AMAX(i);
if (i == A_STR && u.uhs >= 3) --lim; /* WEAK */
if (ABASE(i) < lim) {
ABASE(i) = lim;
flags.botl = 1;
/* only first found if not blessed */
if (!amp->blessed) break;
}
if(++i >= A_MAX) i = 0;
}
}
break;
case POT_BLINDNESS:
if(Blind) nothing++;
make_blinded(itimeout_incr(Blinded,
rn1(200, 250 - 125 * bcsign(amp))),
(boolean)!Blind);
break;
case POT_CONFUSION:
if(!Confusion)
if (Hallucination) {
pline("What a trippy feeling!");
} else pline("Huh, What? Where am I?");
else nothing++;
make_confused(itimeout_incr(HConfusion,
rn1(7, 16 - 8 * bcsign(amp))),
FALSE);
break;
case POT_PARALYSIS:
if (Free_action)
You("stiffen momentarily.");
else {
if (Levitation || Weightless || Is_waterlevel(&u.uz))
You("are motionlessly suspended.");
else if (u.usteed)
You("are frozen in place!");
else
Your("%s are frozen to the %s!",
makeplural(body_part(FOOT)), surface(u.ux, u.uy));
nomul(-(rn1(10, 25 - 12*bcsign(amp))), "frozen by a potion");
nomovemsg = You_can_move_again;
exercise(A_DEX, FALSE);
}
break;
case POT_SPEED:
if(Wounded_legs && !amp->cursed
&& !u.usteed /* heal_legs() would heal steeds legs */
) {
heal_legs();
break;
}
if (!(HFast & INTRINSIC)) {
if (!Fast) You("speed up.");
else Your("quickness feels more natural.");
HFast |= TIMEOUT_INF;
} else nothing++;
exercise(A_DEX, TRUE);
break;
case POT_HALLUCINATION:
if (Hallucination || Halluc_resistance) nothing++;
(void) make_hallucinated(itimeout_incr(HHallucination,
rn1(200, 600 - 300 * bcsign(amp))),
TRUE, 0L);
//Bad drugs: inflict brain damage
if(amp->cursed){
if(u.usanity > 0)
change_usanity(-1, FALSE);
if(u.uinsight > 0)
change_uinsight(-1);
exercise(A_WIS, FALSE);
exercise(A_INT, FALSE);
}
break;
case POT_HEALING:
You_feel("better.");
healup(d(6 + 2 * bcsign(amp), 4),
(!amp->cursed ? 1 : 0), amp->blessed, !amp->cursed);
exercise(A_CON, TRUE);
break;
case POT_EXTRA_HEALING:
You_feel("much better.");
healup(d(6 + 2 * bcsign(amp), 8),
(1+1*bcsign(amp)), !amp->cursed, TRUE);
(void) make_hallucinated(0L,TRUE,0L);
exercise(A_CON, TRUE);
exercise(A_STR, TRUE);
break;
case POT_GAIN_ENERGY:
{ register int num;
num = rnd(2) + 2 * amp->blessed + 1;
u.uenbonus += (amp->cursed) ? -num : num;
calc_total_maxen();
u.uen += (amp->cursed) ? -100 : (amp->blessed) ? 200 : 100;
if(u.uen > u.uenmax) u.uen = u.uenmax;
if(u.uen <= 0 && !Race_if(PM_INCANTIFIER)) u.uen = 0;
flags.botl = 1;
if(!amp->cursed) exercise(A_WIS, TRUE);
//Doing the print last causes the bottom line update to show the changed energy scores.
if(amp->cursed)
You_feel("lackluster.");
else
pline("Magical energies course through your body.");
}
break;
case POT_SLEEPING:
if(Sleep_resistance || Free_action)
You("yawn.");
else {
You("suddenly fall asleep!");
fall_asleep(-rn1(10, 25 - 12*bcsign(amp)), TRUE);
}
//Sedative
change_usanity(5 + 10*bcsign(amp), FALSE);
break;
case POT_FULL_HEALING:
You_feel("completely healed.");
healup(400, (2+2*bcsign(amp)), !amp->cursed, TRUE);
/* Restore one lost level if blessed */
if (amp->blessed && u.ulevel < u.ulevelmax) {
///* when multiple levels have been lost, drinking
// multiple potions will only get half of them back */
// u.ulevelmax -= 1;
pluslvl(FALSE);
}
/* Dissolve one morgul blade shard if blessed*/
if(amp->blessed && u.umorgul>0){
u.umorgul--;
if(u.umorgul)
You_feel("the chill of death lessen.");
else
You_feel("the chill of death fade away.");
}
if(amp->blessed && u.umummyrot){
u.umummyrot = 0;
You("stop shedding dust.");
}
(void) make_hallucinated(0L,TRUE,0L);
exercise(A_STR, TRUE);
exercise(A_CON, TRUE);
break;
case POT_POLYMORPH:
You_feel("a little %s.", Hallucination ? "normal" : "strange");
if (!Unchanging) polyself(FALSE);
break;
case POT_AMNESIA:
forget(amp->cursed ? 25 : amp->blessed ? 0 : 10);
if (Hallucination)
pline("Hakuna matata!");
else
You_feel("your memories dissolve.");
/* Blessed amnesia makes you forget lycanthropy, sickness */
if (amp->blessed) {
if (u.ulycn >= LOW_PM && !Race_if(PM_HUMAN_WEREWOLF)) {
You("forget your affinity to %s!",
makeplural(mons[u.ulycn].mname));
if (youmonst.data->mtyp == u.ulycn)
you_unwere(FALSE);
u.ulycn = NON_PM; /* cure lycanthropy */
}
make_sick(0L, (char *) 0, TRUE, SICK_ALL);
/* You feel refreshed */
if(Race_if(PM_INCANTIFIER)) u.uen += 50 + rnd(50);
else u.uhunger += 50 + rnd(50);
newuhs(FALSE);
} else {
if(Role_if(PM_MADMAN)){
You_feel("ashamed of wiping your own memory.");
change_hod(amp->cursed ? 5 : 2);
}
exercise(A_WIS, FALSE);
}
//All amnesia causes you to forget your crisis of faith
if(Doubt)
You("forget your doubts.");
make_doubtful(0L, FALSE);
break;
}
if(nothing) {
You("have a %s feeling for a moment, then it passes.",
Hallucination ? "normal" : "peculiar");
}
}
amp->spe--;
return MOVE_STANDARD;
}
/* Place a landmine/bear trap. Helge Hafting */
static void
use_trap(struct obj *otmp)
{
int ttyp, tmp;
const char *what = (char *)0;
char buf[BUFSZ];
const char *occutext = "setting the trap";
if (nohands(youracedata))
what = "without hands";
else if(!freehand())
what = "without free hands";
else if (Stunned)
what = "while stunned";
else if (u.uswallow)
what = is_animal(u.ustuck->data) ? "while swallowed" :
"while engulfed";
else if (Underwater)
what = "underwater";
else if (Levitation)
what = "while levitating";
else if (is_pool(u.ux, u.uy, TRUE))
what = "in water";
else if (is_lava(u.ux, u.uy))
what = "in lava";
else if (On_stairs(u.ux, u.uy))
what = (u.ux == xdnladder || u.ux == xupladder) ?
"on the ladder" : "on the stairs";
else if (IS_FURNITURE(levl[u.ux][u.uy].typ) ||
IS_ROCK(levl[u.ux][u.uy].typ) ||
closed_door(u.ux, u.uy) || t_at(u.ux, u.uy))
what = "here";
if (what) {
You_cant("set a trap %s!",what);
reset_trapset();
return;
}
ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
if (otmp == trapinfo.tobj &&
u.ux == trapinfo.tx && u.uy == trapinfo.ty) {
You("resume setting %s %s.",
shk_your(buf, otmp),
defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
set_occupation(set_trap, occutext, 0);
return;
}
trapinfo.tobj = otmp;
trapinfo.tx = u.ux, trapinfo.ty = u.uy;
tmp = ACURR(A_DEX);
trapinfo.time_needed = (tmp > 17) ? 2 : (tmp > 12) ? 3 :
(tmp > 7) ? 4 : 5;
if (Blind) trapinfo.time_needed *= 2;
tmp = ACURR(A_STR);
if (ttyp == BEAR_TRAP && tmp < 18)
trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4;
/*[fumbling and/or confusion and/or cursed object check(s)
should be incorporated here instead of in set_trap]*/
if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
boolean chance;
if (Fumbling || otmp->cursed) chance = (rnl(100) > 30);
else chance = (rnl(100) > 50);
You("aren't very skilled at reaching from %s.",
mon_nam(u.usteed));
Sprintf(buf, "Continue your attempt to set %s?",
the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
if(yn(buf) == 'y') {
if (chance) {
switch(ttyp) {
case LANDMINE: /* set it off */
trapinfo.time_needed = 0;
trapinfo.force_bungle = TRUE;
break;
case BEAR_TRAP: /* drop it without arming it */
reset_trapset();
You("drop %s!",
the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
dropx(otmp);
return;
}
}
} else {
reset_trapset();
return;
}
}
You("begin setting %s %s.",
shk_your(buf, otmp),
defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
if (otmp->unpaid){
verbalize("You set it, you buy it!");
if (!rn2(3))
verbalize("If you hurt somebody, it's not my fault!");
bill_dummy_object(otmp);
} else if (costly_spot(u.ux, u.uy)) {
verbalize("Don't hurt my customers!");
}
set_occupation(set_trap, occutext, 0);
return;
}
static int
set_trap(void)
{
struct obj *otmp = trapinfo.tobj;
struct trap *ttmp;
int ttyp;
boolean obj_cursed = otmp->cursed;
if (!otmp || !carried(otmp) ||
u.ux != trapinfo.tx || u.uy != trapinfo.ty) {
/* ?? */
reset_trapset();
return MOVE_CANCELLED;
}
if (--trapinfo.time_needed > 0) return MOVE_STANDARD; /* still busy */
ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
ttmp = maketrap(u.ux, u.uy, ttyp);
if (ttmp) {
ttmp->tseen = 1;
ttmp->madeby_u = 1;
newsym(u.ux, u.uy); /* if our hero happens to be invisible */
/* Our object becomes the new ammo of the trap. */
if (otmp->quan > 1) {
otmp = splitobj(otmp, 1);
}
freeinv(otmp);
set_trap_ammo(ttmp, otmp);
if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
add_damage(u.ux, u.uy, 0L); /* schedule removal */
}
if (!trapinfo.force_bungle)
You("finish arming %s.",
the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
if (((obj_cursed || Fumbling) && (rnl(100) > 50)) || trapinfo.force_bungle)
dotrap(ttmp,
(unsigned)(trapinfo.force_bungle ? FORCEBUNGLE : 0));
} else {
/* this shouldn't happen */
Your("trap setting attempt fails.");
}
reset_trapset();
return MOVE_FINISHED_OCCUPATION;
}
static int
use_droven_cloak(struct obj **optr)
{
struct obj *otmp = *optr;
int rx, ry;
const char *what = (char *)0;
struct trap *ttmp;
struct monst *mtmp;
if (!getdir((char *)0) || u.dz < 0) return MOVE_CANCELLED;
if (Stunned || (Confusion && !rn2(5))) confdir();
rx = u.ux + u.dx;
ry = u.uy + u.dy;
mtmp = m_at(rx, ry);
ttmp = t_at(rx, ry);
if (!isok(rx, ry))
what = "here";
else if (Stunned)
what = "while stunned";
else if (u.uswallow)
what = is_animal(u.ustuck->data) ? "while swallowed" :
"while engulfed";
else if (Underwater)
what = "underwater";
else if (Levitation)
what = "while levitating";
else if (is_pool(rx, ry, TRUE))
what = "in water";
else if (is_lava(rx, ry))
what = "in lava";
else if (On_stairs(rx, ry) && !(ttmp && ttmp->ttyp == WEB))
what = (rx == xdnladder || rx == xupladder) ?
"on the ladder" : "on the stairs";
else if (IS_FURNITURE(levl[rx][ry].typ) ||
IS_ROCK(levl[rx][ry].typ) ||
closed_door(rx, ry) || (ttmp && ttmp->ttyp != WEB))
what = "here";
if (what && !(ttmp && ttmp->ttyp == WEB)) {
You_cant("set a trap %s!",what);
reset_trapset();
return MOVE_CANCELLED;
}
if(ttmp) {
if(otmp->oeroded3) otmp->oeroded3--;
pline("The cloak sweeps up a web!");
if(!Is_lolth_level(&u.uz)){ //results in unlimited recharging in lolths domain, no big deal
deltrap(ttmp);
newsym(rx, ry);
}
if(rx==u.ux && ry==u.uy) u.utrap = 0;
else if(mtmp) mtmp->mtrapped = 0;
}
else if(!(otmp->oartifact) || otmp->oeroded3 < 3){
ttmp = maketrap(rx, ry, WEB);
if(ttmp){
pline("A web spins out from the cloak!");
ttmp->madeby_u = 1;
ttmp->tseen = 1;
newsym(rx, ry);
if (*in_rooms(rx,ry,SHOPBASE)) {
add_damage(rx, ry, 0L); /* schedule removal */
}
if(rx==u.ux && ry==u.uy) dotrap(ttmp, NOWEBMSG);
else if(mtmp) mintrap(mtmp);
} else pline("The cloak cannot spin a web there!");
if(otmp->oeroded3 == 3){
useup(otmp);
*optr = 0;
pline("The thoroughly tattered cloak falls to pieces");
} else otmp->oeroded3++;
} else {
pline("The cloak cannot spin any more webs.");
return MOVE_CANCELLED;
}
reset_trapset();
return MOVE_STANDARD;
}
static int
use_darkweavers_cloak(struct obj *otmp)
{
const char *what = (char *)0;
if (Stunned)
what = "while stunned";
else if (u.uswallow)
what = is_animal(u.ustuck->data) ? "while swallowed" :
"while engulfed";
else if (Underwater)
what = "underwater";
if (what) {
You_cant("release darkness %s!",what);
return MOVE_CANCELLED;
}
if(!levl[u.ux][u.uy].lit) {
if(otmp->spe < 7) otmp->spe++;
pline("The cloak sweeps up the dark!");
litroom(TRUE, otmp); /* only needs to be done once */
}
else if(otmp->spe > -5){
otmp->spe--;
pline("The cloak releases a cloud of darkness!");
litroom(FALSE, otmp); /* only needs to be done once */
}
return MOVE_STANDARD;
}
static int
use_eilistran_armor(struct obj **optr)
{
struct obj *otmp = *optr;
winid tmpwin;
anything any;
menu_item *selected;
int n;
any.a_void = 0; /* zero out all bits */
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
if(otmp->ovar1_eilistran_charges > 0){
any.a_int = 1;
add_menu(tmpwin, NO_GLYPH, &any , 't', 0, ATR_NONE,
(otmp->altmode == EIL_MODE_ON) ? "Turn off." : "Turn on.", MENU_UNSELECTED);
}
if(otmp->ovar1_eilistran_charges <= 540){
any.a_int = 2;
add_menu(tmpwin, NO_GLYPH, &any , 'r', 0, ATR_NONE,
"Replace worn components.", MENU_UNSELECTED);
}
end_menu(tmpwin, "Do what?");
n = select_menu(tmpwin, PICK_ONE, &selected);
if(n > 0){
n = selected[0].item.a_int;
free(selected);
}
destroy_nhwindow(tmpwin);
if(!n)
return MOVE_CANCELLED;
switch(n){
case 1:
if(otmp->altmode == EIL_MODE_ON){
otmp->altmode = EIL_MODE_OFF;
You("Switch the armor off.");
return MOVE_PARTIAL;
}
else {
otmp->altmode = EIL_MODE_ON;
You("Switch the armor on.");
return MOVE_PARTIAL;
}
break;
case 2:{
struct obj *component = getobj(tools, "replace with");
if(!component)
return MOVE_CANCELLED;
else if(component->otyp != CLOCKWORK_COMPONENT){
pline("This device requires clockwork components.");
return MOVE_CANCELLED;
}
else if(component->cursed){
pline("The component won't go into the mechanism!");
return MOVE_STANDARD;
}
//else
useup(component);
You("put the new component into the armor's mechanism.");
otmp->ovar1_eilistran_charges += 60;
return MOVE_STANDARD;
}break;
}
return MOVE_STANDARD;
}
int
use_whip(struct obj *obj)
{
char buf[BUFSZ];
struct monst *mtmp;
struct obj *otmp;
int rx, ry, proficient, res = MOVE_CANCELLED;
const char *msg_slipsfree = "The whip slips free.";
const char *msg_snap = "Snap!";
boolean ranged = FALSE;
if (obj != uwep) {
if (!wield_tool(obj, "lash")) return MOVE_CANCELLED;
else res = MOVE_STANDARD;
}
if(Straitjacketed){
You("can't snap a whip while your %s are bound!", makeplural(body_part(ARM)));
return MOVE_CANCELLED;
}
if (!getdir((char *)0)) return res;
if(obj->otyp == FORCE_WHIP && !u.dx && !u.dy && !u.dz){
return use_force_sword(obj);
}
if (Stunned || (Confusion && !rn2(5))) confdir();
rx = u.ux + u.dx;
ry = u.uy + u.dy;
if (!isok(rx,ry)) {
pline("%s",msg_snap);
return MOVE_STANDARD;
}
mtmp = m_at(rx, ry);
if(obj->oartifact == ART_GOLDEN_SWORD_OF_Y_HA_TALLA && ZAP_POS(levl[rx][ry].typ)){
if(u.utrap && u.utraptype == TT_PIT){
if(!mtmp && !IS_FURNITURE(levl[rx][ry].typ) && !boulder_at(rx, ry)){
rx = rx + u.dx;
ry = ry + u.dy;
ranged = TRUE;
}
}
else if(!mtmp){
rx = rx + u.dx;
ry = ry + u.dy;
ranged = TRUE;
}
if (!isok(rx,ry)) {
pline("%s",msg_snap);
return MOVE_STANDARD;
}
mtmp = m_at(rx, ry);
}
/* proficiency check */
proficient = P_SKILL(P_WHIP)-P_UNSKILLED;
if (Role_if(PM_ARCHEOLOGIST)) ++proficient;
if (ACURR(A_DEX) < 6) proficient--;
else if (ACURR(A_DEX) >= 14) proficient += (ACURR(A_DEX) - 11)/3;
if (Fumbling) --proficient;
if (proficient > 3) proficient = 3;
if (proficient < 0) proficient = 0;
if (u.uswallow && attack2(u.ustuck)) {
There("is not enough room to flick your whip.");
} else if (Underwater) {
There("is too much resistance to flick your whip.");
} else if (u.dz < 0) {
You("flick a bug off of the %s.",ceiling(u.ux,u.uy));
} else if ((!u.dx && !u.dy) || (u.dz > 0)) {
int dam;
/* Sometimes you hit your steed by mistake */
if (u.usteed && !rn2(proficient + 2)) {
You("whip %s!", mon_nam(u.usteed));
kick_steed();
return MOVE_STANDARD;
}
if (Levitation
|| u.usteed
) {
/* Have a shot at snaring something on the floor */
otmp = level.objects[u.ux][u.uy];
if (otmp && otmp->otyp == CORPSE && otmp->corpsenm == PM_HORSE) {
pline("Why beat a dead horse?");
return MOVE_STANDARD;
}
if (otmp && proficient) {
You("wrap your whip around %s on the %s.",
an(singular(otmp, xname)), surface(u.ux, u.uy));
if (rnl(100) >= 16 || pickup_object(otmp, 1L, TRUE) < 1)
pline("%s", msg_slipsfree);
return MOVE_STANDARD;
}
}
dam = rnd(2) + dbon(obj, &youmonst) + obj->spe;
if (dam <= 0) dam = 1;
You("hit your %s with your whip.", body_part(FOOT));
Sprintf(buf, "killed %sself with %s whip", uhim(), uhis());
losehp(dam, buf, NO_KILLER_PREFIX);
flags.botl = 1;
return MOVE_STANDARD;
} else if ((Fumbling || Glib) && !rn2(5)) {
pline_The("whip slips out of your %s.", body_part(HAND));
dropx(obj);
} else if (u.utrap && u.utraptype == TT_PIT) {
/*
* Assumptions:
*
* if you're in a pit
* - you are attempting to get out of the pit
* - or, if you are applying it towards a small
* monster then it is assumed that you are
* trying to hit it.
* else if the monster is wielding a weapon
* - you are attempting to disarm a monster
* else
* - you are attempting to hit the monster
*
* if you're confused (and thus off the mark)
* - you only end up hitting.
*
*/
const char *wrapped_what = (char *)0;
if (mtmp) {
if (bigmonst(mtmp->data)) {
wrapped_what = strcpy(buf, mon_nam(mtmp));
} else if (proficient) {
struct attack attk = {AT_WEAP, AD_PHYS, 0, 0};
if (ranged ? (xmeleehity(&youmonst, mtmp, &attk, &otmp, -1, 0, TRUE) != MM_AGR_DIED) : attack2(mtmp)) return MOVE_ATTACKED;
else pline("%s", msg_snap);
}
}
if (!wrapped_what) {
if (IS_FURNITURE(levl[rx][ry].typ))
wrapped_what = something;
else if (boulder_at(rx, ry))
wrapped_what = xname(boulder_at(rx,ry));
}
if (wrapped_what) {
coord cc;
cc.x = rx; cc.y = ry;
You("wrap your whip around %s.", wrapped_what);
if (proficient && rn2(proficient + 2)) {
if (!mtmp || enexto(&cc, rx, ry, youracedata)) {
You("yank yourself out of the pit!");
teleds(cc.x, cc.y, TRUE);
u.utrap = 0;
vision_full_recalc = 1;
}
} else {
pline("%s", msg_slipsfree);
}
if (mtmp) wakeup(mtmp, TRUE);
} else pline("%s", msg_snap);
} else if (mtmp) {
if (!canspotmon(mtmp) &&
!glyph_is_invisible(levl[rx][ry].glyph)) {
pline("A monster is there that you couldn't see.");
map_invisible(rx, ry);
}
otmp = rn2(3) ? MON_WEP(mtmp) : MON_SWEP(mtmp); /* can be null */
if (otmp) {
char onambuf[BUFSZ];
const char *mon_hand;
boolean gotit = proficient && (!Fumbling || !rn2(10));
Strcpy(onambuf, cxname(otmp));
if (gotit) {
mon_hand = mbodypart(mtmp, HAND);
if (bimanual(otmp,mtmp->data)) mon_hand = makeplural(mon_hand);
} else
mon_hand = 0; /* lint suppression */
You("wrap your whip around %s %s.",
s_suffix(mon_nam(mtmp)), onambuf);
if (gotit && otmp->cursed && !is_weldproof_mon(mtmp)) {
pline("%s welded to %s %s%c",
(otmp->quan == 1L) ? "It is" : "They are",
mhis(mtmp), mon_hand,
!otmp->bknown ? '!' : '.');
otmp->bknown = 1;
gotit = FALSE; /* can't pull it free */
}
if (gotit) {
obj_extract_self(otmp);
possibly_unwield(mtmp, FALSE);
setmnotwielded(mtmp,otmp);
switch (rn2(proficient + 1)) {
case 2:
/* to floor near you */
You("yank %s %s to the %s!", s_suffix(mon_nam(mtmp)),
onambuf, surface(u.ux, u.uy));
place_object(otmp, u.ux, u.uy);
stackobj(otmp);
break;
case 3:
/* right to you */
#if 0
if (!rn2(25)) {
/* proficient with whip, but maybe not
so proficient at catching weapons */
int hitu, hitvalu;
int dieroll;
hitvalu = tohitval((struct monst *)0, &youmonst, (struct attack *)0, otmp, (void *)0, HMON_PROJECTILE, 8, (int *) 0);
if(hitvalu > (dieroll = rnd(20)) || (dieroll == 1 && hitvalu > -10)) {
boolean wepgone = FALSE;
pline_The("%s hits you as you try to snatch it!" the(onambuf));
hmon_general((struct monst *)0, &youmonst, (struct attack *)0, &otmp, (void *)0, HMON_PROJECTILE,
0, 0, FALSE, dieroll, FALSE, -1);
}
else {
if(Blind || !flags.verbose) pline("It misses.");
else You("are almost hit by %s.", the(onambuf));
}
place_object(otmp, u.ux, u.uy);
stackobj(otmp);
break;
}
#endif /* 0 */
/* right into your inventory */
You("snatch %s %s!", s_suffix(mon_nam(mtmp)), onambuf);
if (otmp->otyp == CORPSE &&
touch_petrifies(&mons[otmp->corpsenm]) &&
!uarmg && !Stone_resistance &&
!(poly_when_stoned(youracedata) &&
polymon(PM_STONE_GOLEM))) {
char kbuf[BUFSZ];
Sprintf(kbuf, "%s corpse",
an(mons[otmp->corpsenm].mname));
pline("Snatching %s is a fatal mistake.", kbuf);
instapetrify(kbuf);
}
otmp = hold_another_object(otmp, "You drop %s!",
doname(otmp), (const char *)0);
break;
default:
/* to floor beneath mon */
You("yank %s from %s %s!", the(onambuf),
s_suffix(mon_nam(mtmp)), mon_hand);
obj_no_longer_held(otmp);
place_object(otmp, mtmp->mx, mtmp->my);
stackobj(otmp);
break;
}
} else {
pline("%s", msg_slipsfree);
}
wakeup(mtmp, TRUE);
} else {
if ((mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER) &&
!Protection_from_shape_changers && !sensemon(mtmp))
stumble_onto_mimic(mtmp);
else You("flick your whip towards %s.", mon_nam(mtmp));
if (proficient) {
struct attack attk = {AT_WEAP, AD_PHYS, 0, 0};
if (ranged ? (xmeleehity(&youmonst, mtmp, &attk, &otmp, -1, 0, TRUE) != MM_AGR_DIED) : attack2(mtmp)) return MOVE_ATTACKED;
else pline("%s", msg_snap);
}
}
} else if (Weightless || Is_waterlevel(&u.uz)) {
/* it must be air -- water checked above */
You("snap your whip through thin air.");
} else {
pline("%s", msg_snap);
}
return MOVE_STANDARD;
}
int
use_nunchucks(struct obj *obj)
{
char buf[BUFSZ];
struct monst *mtmp;
struct obj *otmp;
int rx, ry, proficient, res = MOVE_CANCELLED;
const char *msg_slipsfree = "The nunchaku slip free.";
const char *msg_snap = "Swish!";
if (obj != uwep) {
if (!wield_tool(obj, "nunchaku")) return MOVE_CANCELLED;
else res = Role_if(PM_MONK) ? MOVE_PARTIAL : MOVE_STANDARD;
}
if(Straitjacketed){
You("can't swing nunchaku while your %s are bound!", makeplural(body_part(ARM)));
return MOVE_CANCELLED;
}
if (!getdir((char *)0)) return res;
else res = Role_if(PM_MONK) ? MOVE_PARTIAL : MOVE_STANDARD;
if (Stunned || (Confusion && !rn2(5))) confdir();
rx = u.ux + u.dx;
ry = u.uy + u.dy;
if (!isok(rx,ry)) {
pline("%s",msg_snap);
return res;
}
mtmp = m_at(rx, ry);
/* proficiency check */
proficient = 0;
if(martial_bonus()){
proficient = min(P_SKILL(P_FLAIL)-P_UNSKILLED, P_SKILL(P_MARTIAL_ARTS)-P_BASIC);
}
if (Role_if(PM_MONK)) ++proficient;
if (ACURR(A_DEX) < 6) proficient--;
else if (ACURR(A_DEX) >= 14) proficient += (ACURR(A_DEX) - 11)/3;
if (Fumbling) --proficient;
if (proficient > 3) proficient = 3;
if (proficient < 0) proficient = 0;
if (u.uswallow && attack2(u.ustuck)) {
There("is not enough room to swing your nunchaku.");
} else if (Underwater) {
There("is too much resistance to swing your nunchaku.");
} else if (u.dz < 0) {
if(!Levitation && !Flying)
You("glare impotently at the bugs on the %s.",ceiling(u.ux,u.uy));
else
You("smash a bug on the %s.",ceiling(u.ux,u.uy));
} else if ((!u.dx && !u.dy) || (u.dz > 0)) {
int dam;
dam = rnd(4) + dbon(obj, &youmonst) + obj->spe;
if (dam <= 0) dam = 1;
You("hit your %s with your nunchaku.", body_part((u.dz > 0) ? FOOT : HAND));
Sprintf(buf, "killed %sself with %s whip", uhim(), uhis());
losehp(dam, buf, NO_KILLER_PREFIX);
flags.botl = 1;
return MOVE_STANDARD;
} else if ((Fumbling || Glib) && !rn2(5)) {
pline_The("nunchaku slips out of your %s.", body_part(HAND));
dropx(obj);
} else if (mtmp) {
if (!canspotmon(mtmp) &&
!glyph_is_invisible(levl[rx][ry].glyph)) {
pline("A monster is there that you couldn't see.");
map_invisible(rx, ry);
}
otmp = rn2(3) ? MON_WEP(mtmp) : MON_SWEP(mtmp); /* can be null */
if (otmp) {
char onambuf[BUFSZ];
const char *mon_hand;
boolean gotit = proficient && (!Fumbling || !rn2(10));
Strcpy(onambuf, cxname(otmp));
if (gotit) {
mon_hand = mbodypart(mtmp, HAND);
if (bimanual(otmp,mtmp->data)) mon_hand = makeplural(mon_hand);
} else
mon_hand = 0; /* lint suppression */
You("wrap your nunchaku-chain around %s %s.",
s_suffix(mon_nam(mtmp)), onambuf);
if (gotit && otmp->cursed && !is_weldproof_mon(mtmp)) {
pline("%s welded to %s %s%c",
(otmp->quan == 1L) ? "It is" : "They are",
mhis(mtmp), mon_hand,
!otmp->bknown ? '!' : '.');
otmp->bknown = 1;
gotit = FALSE; /* can't pull it free */
}
if (gotit) {
obj_extract_self(otmp);
possibly_unwield(mtmp, FALSE);
setmnotwielded(mtmp,otmp);
switch (rn2(proficient + 1)) {
case 2:
/* to floor near you */
You("yank %s %s to the %s!", s_suffix(mon_nam(mtmp)),
onambuf, surface(u.ux, u.uy));
place_object(otmp, u.ux, u.uy);
stackobj(otmp);
break;
case 3:
/* right to you */
/* right into your inventory */
You("snatch %s %s!", s_suffix(mon_nam(mtmp)), onambuf);
if (otmp->otyp == CORPSE &&
touch_petrifies(&mons[otmp->corpsenm]) &&
!uarmg && !Stone_resistance &&
!(poly_when_stoned(youracedata) &&
polymon(PM_STONE_GOLEM))
){
char kbuf[BUFSZ];
Sprintf(kbuf, "%s corpse",
an(mons[otmp->corpsenm].mname));
pline("Snatching %s is a fatal mistake.", kbuf);
instapetrify(kbuf);
}
otmp = hold_another_object(otmp, "You drop %s!",
doname(otmp), (const char *)0);
break;
default:
/* to floor beneath mon */
You("yank %s from %s %s!", the(onambuf),
s_suffix(mon_nam(mtmp)), mon_hand);
obj_no_longer_held(otmp);
place_object(otmp, mtmp->mx, mtmp->my);
stackobj(otmp);
break;
}
} else {
pline("%s", msg_slipsfree);
}
wakeup(mtmp, TRUE);
} else {
res |= MOVE_ATTACKED;
if ((mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER) &&
!Protection_from_shape_changers && !sensemon(mtmp))
stumble_onto_mimic(mtmp);
else You("swing your nunchaku toward %s.", mon_nam(mtmp));
if (proficient) {
if (attack2(mtmp)) return res;
else pline("%s", msg_snap);
}
}
} else if (Weightless || Is_waterlevel(&u.uz)) {
/* it must be air -- water checked above */
You("swing your nunchaku through thin air.");
} else {
pline("%s", msg_snap);
}
return res;
}
//Used to coordinate polearm_menu and targeting code
const int pole_dy[16] = {-2,-2,-2,-1, 0, 1, 2, 2, 2, 2, 2, 1, 0,-1,-2,-2};
const int pole_dx[16] = { 0, 1, 2, 2, 2, 2, 2, 1, 0,-1,-2,-2,-2,-2,-2,-1};
const char pole_dir[16][4] = {"N","NNE","NE",
"ENE","E","ESE","SE",
"SSE","S","SSW","SW",
"WSW","W","WNW","NW",
"NNW"};
#define N_POLEDIRS 16
static int
polearm_menu(struct obj *pole)
{
winid tmpwin;
int n = 0, how, i, cx, cy;
int typ, max_range;
struct monst *mtmp;
char buf[BUFSZ];
char incntlet;
menu_item *selected;
anything any;
/* Calculate range */
typ = weapon_type(pole);
int skill = P_SKILL(typ);
if(pole->otyp == POLEAXE)
skill--;
if (typ == P_NONE || skill <= P_BASIC) max_range = 4;
else if ( skill == P_SKILLED) max_range = 5;
else max_range = 8;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Targets");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
incntlet = 'a';
for(i=0; i<16; i++){
cx = u.ux + pole_dx[i];
cy = u.uy + pole_dy[i];
if(isok(cx, cy) && (mtmp = m_at(cx, cy))
&& canseemon(mtmp)
&& couldsee(cx, cy)
&& distu(cx, cy) <= max_range
&& !(mtmp->mappearance && mtmp->m_ap_type != M_AP_MONSTER && !sensemon(mtmp))
&& !(flags.peacesafe_polearms && mtmp->mpeaceful && !Hallucination)
&& !(flags.petsafe_polearms && mtmp->mtame && !Hallucination)
){
Sprintf(buf, "%s (%s)", Monnam(mtmp), pole_dir[i]);
any.a_int = i+1; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
else if(!flags.relative_polearms)
incntlet++; /* always increment, so that the same direction is always the same letter*/
}
/* add an option to target manually */
Sprintf(buf, "(some location)");
any.a_int = N_POLEDIRS+1;
add_menu(tmpwin, NO_GLYPH, &any,
'z', 0, ATR_NONE, buf,
MENU_UNSELECTED);
end_menu(tmpwin, "Choose target:");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n > 0){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
static const char
not_enough_room[] = "There's not enough room here to use that.",
where_to_hit[] = "Where do you want to hit?",
cant_see_spot[] = "won't hit anything if you can't see that spot.",
cant_reach[] = "can't reach that spot from here.";
/*Note: If input is invalid or cancelled, may return MOVE_CANCELLED OR MOVE_STANDARD
* MOVE_STANDARD: The PC wielded the polearm before failing to give input.
* MOVE_CANCELLED: The PC either failed to wield the pole, or was already wielding it before failing to give input.
* If input succeeds, MOVE_STANDARD is returned.
*
* If input fails, cc should be set to 0,0 and *outptr should be 0.
* The caller should therefor always check isok() before using the coordinates.
*/
static int
pick_polearm_target(struct obj *obj, struct monst **outptr, coord *ccp)
{
int res = MOVE_CANCELLED, typ, max_range = 4, min_range = 4;
int i;
struct monst *mtmp = (struct monst *) 0;
*outptr = (struct monst *) 0;
ccp->x = 0; ccp->y = 0;
/* Are you allowed to use the pole? */
if (u.uswallow) {
pline("%s", not_enough_room);
return MOVE_CANCELLED;
}
if (obj != uwep && obj != uarmg) {
if (!wield_tool(obj, "swing")) return MOVE_CANCELLED;
else res = MOVE_STANDARD;
}
if(Straitjacketed){
You("can't swing a polearm while your %s are bound!", makeplural(body_part(ARM)));
return MOVE_CANCELLED;
}
/* assert(obj == uwep); */
/* Prompt for a location */
if(flags.standard_polearms){
pline("%s", where_to_hit);
ccp->x = u.ux;
ccp->y = u.uy;
if (getpos(ccp, TRUE, "the spot to hit") < 0){
ccp->x = 0; ccp->y = 0;
return res; /* user pressed ESC */
}
}
else {
if((i = polearm_menu(uwep))){
i--; /*Remove the off-by-one offset used to make all returns from polearm_menu non-zero*/
if (i<N_POLEDIRS) {
ccp->x = u.ux + pole_dx[i];
ccp->y = u.uy + pole_dy[i];
}
else {
/* use standard targeting; save retval to return */
flags.standard_polearms = TRUE;
int retval = pick_polearm_target(obj,outptr,ccp);
flags.standard_polearms = FALSE;
if(res == MOVE_STANDARD || retval == MOVE_STANDARD)
return MOVE_STANDARD;
return res | retval;
}
}
else {
ccp->x = 0; ccp->y = 0;
return res; /* user pressed ESC */
}
}
/* Calculate range */
typ = uwep_skill_type();
int skill = P_SKILL(typ);
if(obj->otyp == POLEAXE)
skill--;
if (typ == P_NONE || skill <= P_BASIC) max_range = 4;
else if ( skill == P_SKILLED) max_range = 5;
else max_range = 8;
mtmp = m_at(ccp->x, ccp->y);
if (distu(ccp->x, ccp->y) > max_range) {
pline("Too far!");
ccp->x = 0; ccp->y = 0;
return (res);
} else if (distu(ccp->x, ccp->y) < min_range) {
pline("Too close!");
ccp->x = 0; ccp->y = 0;
return (res);
} else if (!cansee(ccp->x, ccp->y) &&
(mtmp == (struct monst *)0 ||
!canseemon(mtmp))) {
You(cant_see_spot);
ccp->x = 0; ccp->y = 0;
return (res);
} else if (!couldsee(ccp->x, ccp->y)) { /* Eye of the Overworld */
You(cant_reach);
ccp->x = 0; ccp->y = 0;
return res;
}
*outptr = mtmp;
return MOVE_STANDARD;
}
/* Distance attacks by pole-weapons */
static int
use_pole(struct obj *obj)
{
coord cc = {0};
struct monst *mtmp;
int res = pick_polearm_target(obj, &mtmp, &cc);
if(!isok(cc.x, cc.y))
return res;
/* Attack the monster there */
if (mtmp) {
bhitpos = cc;
check_caitiff(mtmp);
if (u_pole_pound(mtmp)) {
u.uconduct.weaphit++;
}
} else if(levl[cc.x][cc.y].typ == GRASS){
levl[cc.x][cc.y].typ = SOIL;
if(!rn2(3)) mksobj_at(SHEAF_OF_HAY,cc.x,cc.y,NO_MKOBJ_FLAGS);
You("cut away the grass!");
newsym(cc.x,cc.y);
} else {
/* Now you know that nothing is there... */
pline("%s", nothing_happens);
}
return MOVE_ATTACKED;
}
static int
use_cream_pie(struct obj *obj)
{
boolean wasblind = Blind;
boolean wascreamed = u.ucreamed;
boolean several = FALSE;
if (obj->quan > 1L) {
several = TRUE;
obj = splitobj(obj, 1L);
}
if (Hallucination)
You("give yourself a facial.");
else
pline("You immerse your %s in %s%s.", body_part(FACE),
several ? "one of " : "",
several ? makeplural(the(xname(obj))) : the(xname(obj)));
if(can_blnd((struct monst*)0, &youmonst, AT_WEAP, obj)) {
int blindinc = rnd(25);
u.ucreamed += blindinc;
make_blinded(Blinded + (long)blindinc, FALSE);
if (!Blind || (Blind && wasblind))
pline("There's %ssticky goop all over your %s.",
wascreamed ? "more " : "",
body_part(FACE));
else /* Blind && !wasblind */
You_cant("see through all the sticky goop on your %s.",
body_part(FACE));
}
if (obj->unpaid) {
verbalize("You used it, you bought it!");
bill_dummy_object(obj);
}
obj_extract_self(obj);
delobj(obj);
return MOVE_INSTANT;
}
static int
use_grapple(struct obj *obj)
{
int res = MOVE_CANCELLED, typ, max_range = 4, tohit;
coord cc = {0};
struct monst *mtmp;
struct obj *otmp;
/* Are you allowed to use the hook? */
if (u.uswallow) {
pline("%s", not_enough_room);
return MOVE_CANCELLED;
}
if (obj != uwep) {
if (!wield_tool(obj, "cast")) return MOVE_CANCELLED;
else res = MOVE_STANDARD;
}
if(Straitjacketed){
You("can't cast a grappling hook while your %s are bound!", makeplural(body_part(ARM)));
return MOVE_CANCELLED;
}
/* assert(obj == uwep); */
/* Prompt for a location */
pline("%s", where_to_hit);
cc.x = u.ux;
cc.y = u.uy;
if (getpos(&cc, TRUE, "the spot to hit") < 0)
return res; /* user pressed ESC */
/* Calculate range */
typ = uwep_skill_type();
if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
else max_range = 8;
if(obj->oartifact == ART_PUPPET_WIRE) max_range = 8;
if (distu(cc.x, cc.y) > max_range) {
pline("Too far!");
return (res);
} else if (!cansee(cc.x, cc.y)) {
You(cant_see_spot);
return (res);
} else if (!couldsee(cc.x, cc.y)) { /* Eye of the Overworld */
You(cant_reach);
return res;
}
/* What do you want to hit? */
tohit = rn2(5);
if(obj->oartifact == ART_PUPPET_WIRE) tohit = 2;
else if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) {
winid tmpwin = create_nhwindow(NHW_MENU);
anything any;
char buf[BUFSZ];
menu_item *selected;
any.a_void = 0; /* set all bits to zero */
any.a_int = 1; /* use index+1 (cant use 0) as identifier */
start_menu(tmpwin);
any.a_int++;
Sprintf(buf, "an object on the %s", surface(cc.x, cc.y));
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
buf, MENU_UNSELECTED);
any.a_int++;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
"a monster", MENU_UNSELECTED);
any.a_int++;
Sprintf(buf, "the %s", surface(cc.x, cc.y));
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
buf, MENU_UNSELECTED);
end_menu(tmpwin, "Aim for what?");
tohit = rn2(4);
if (select_menu(tmpwin, PICK_ONE, &selected) > 0 &&
rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2)
)
tohit = selected[0].item.a_int - 1;
free((void *)selected);
destroy_nhwindow(tmpwin);
}
/* What did you hit? */
switch (tohit) {
case 0: /* Trap */
/* FIXME -- untrap needs to deal with non-adjacent traps */
break;
case 1: /* Object */
if ((otmp = level.objects[cc.x][cc.y]) != 0) {
You("snag an object from the %s!", surface(cc.x, cc.y));
(void) pickup_object(otmp, 1L, FALSE);
/* If pickup fails, leave it alone */
newsym(cc.x, cc.y);
return MOVE_STANDARD;
}
break;
case 2: /* Monster */
if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0) break;
if ((obj->oartifact == ART_PUPPET_WIRE || (verysmall(mtmp->data) && !rn2(4))) &&
enexto(&cc, u.ux, u.uy, (struct permonst *)0)) {
You("pull in %s!", mon_nam(mtmp));
mtmp->mundetected = 0;
rloc_to(mtmp, cc.x, cc.y);
return MOVE_STANDARD;
}
else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data)) || rn2(4)) {
u_pole_pound(mtmp);
return MOVE_ATTACKED;
}
/* FALL THROUGH */
case 3: /* Surface */
if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y, TRUE))
pline_The("hook slices through the %s.", surface(cc.x, cc.y));
else {
You("are yanked toward the %s!", surface(cc.x, cc.y));
hurtle(sgn(cc.x-u.ux), sgn(cc.y-u.uy), 1, FALSE, TRUE);
spoteffects(TRUE);
}
return MOVE_STANDARD;
default: /* Yourself (oops!) */
if (P_SKILL(typ) <= P_BASIC) {
You("hook yourself!");
losehp(rn1(10,10), "a grappling hook", KILLED_BY);
return MOVE_STANDARD;
}
break;
}
pline("%s", nothing_happens);
return MOVE_STANDARD;
}
static int
use_crook(struct obj *obj)
{
int res = MOVE_CANCELLED, typ, max_range = 4, tohit;
coord cc = {0};
struct monst *mtmp;
struct obj *otmp;
/* Are you allowed to use the crook? */
if (u.uswallow) {
pline("%s", not_enough_room);
return MOVE_CANCELLED;
}
if (obj != uwep) {
if (!wield_tool(obj, "hook")) return MOVE_CANCELLED;
else res = MOVE_STANDARD;
}
if(Straitjacketed){
You("can't use a shepherd's crook while your %s are bound!", makeplural(body_part(ARM)));
return MOVE_CANCELLED;
}
/* assert(obj == uwep); */
/* What do you want to hit? */
{
winid tmpwin = create_nhwindow(NHW_MENU);
anything any;
char buf[BUFSZ];
menu_item *selected;
any.a_void = 0; /* set all bits to zero */
any.a_int = 1; /* use index+1 (cant use 0) as identifier */
start_menu(tmpwin);
any.a_int++;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
"hit a monster", MENU_UNSELECTED);
any.a_int++;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
"pull a monster", MENU_UNSELECTED);
any.a_int++;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
"pull an object", MENU_UNSELECTED);
end_menu(tmpwin, "Aim for what?");
if (select_menu(tmpwin, PICK_ONE, &selected) > 0){
tohit = selected[0].item.a_int - 1;
}
else {
free((void *)selected);
destroy_nhwindow(tmpwin);
return MOVE_CANCELLED;
}
free((void *)selected);
destroy_nhwindow(tmpwin);
}
typ = uwep_skill_type();
/* What did you hit? */
switch (tohit) {
case 0: /* Trap */
/* FIXME -- untrap needs to deal with non-adjacent traps */
break;
case 1: /*Hit Monster */
res |= use_pole(obj);
if(res & MOVE_STANDARD)
return MOVE_STANDARD;
return res;
break;
case 2: /*Hook Monster */
res |= pick_polearm_target(obj, &mtmp, &cc);
if(!mtmp){
if(res & MOVE_STANDARD)
return MOVE_STANDARD;
return res;
}
if(mtmp->mpeaceful){
if (!bigmonst(mtmp->data) &&
enexto(&cc, u.ux, u.uy, (struct permonst *)0)
) {
You("pull in %s!", mon_nam(mtmp));
mtmp->mundetected = 0;
mtmp->movement = max(0, mtmp->movement - 12);
rloc_to(mtmp, cc.x, cc.y);
return MOVE_STANDARD;
} else {
You("pull yourself toward %s!", mon_nam(mtmp));
hurtle(sgn(mtmp->mx-u.ux), sgn(mtmp->my-u.uy), 1, FALSE, TRUE);
spoteffects(TRUE);
return MOVE_STANDARD;
}
} else {
if (!bigmonst(mtmp->data) && !strongmonst(mtmp->data) && rn2(P_SKILL(typ)) &&
enexto(&cc, u.ux, u.uy, (struct permonst *)0)
) {
You("pull in %s!", mon_nam(mtmp));
mtmp->mundetected = 0;
mtmp->movement = max(0, mtmp->movement - 12);
rloc_to(mtmp, cc.x, cc.y);
return MOVE_STANDARD;
} else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data)) ||
rn2(P_SKILL(typ))
) {
u_pole_pound(mtmp);
return MOVE_ATTACKED;
} else {
You("are yanked toward %s!", mon_nam(mtmp));
hurtle(sgn(mtmp->mx-u.ux), sgn(mtmp->my-u.uy), 1, FALSE, TRUE);
spoteffects(TRUE);
return MOVE_STANDARD;
}
}
break;
case 3: /* Object */
{
int tmp = flags.standard_polearms;
int subres;
flags.standard_polearms = 1;
subres = pick_polearm_target(obj, &mtmp, &cc);
flags.standard_polearms = tmp;
//Note: May have wielded polearm.
if (!isok(cc.x, cc.y))
return res;
}
if ((otmp = level.objects[cc.x][cc.y]) != 0) {
You("snag an object from the %s!", surface(cc.x, cc.y));
(void) pickup_object(otmp, 1L, FALSE);
/* If pickup fails, leave it alone */
newsym(cc.x, cc.y);
return MOVE_STANDARD;
}
break;
// case 3: /* Surface */
// if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y, TRUE))
// pline_The("hook slices through the %s.", surface(cc.x, cc.y));
// else {
// You("are yanked toward the %s!", surface(cc.x, cc.y));
// hurtle(sgn(cc.x-u.ux), sgn(cc.y-u.uy), 1, FALSE, TRUE);
// spoteffects(TRUE);
// }
// return MOVE_STANDARD;
// break;
default:
pline("Invalid target for crook-hook");
break;
}
pline("%s", nothing_happens);
return MOVE_STANDARD;
}
static int
use_rift(struct obj *obj)
{
struct monst *mtmp = 0;
if(!freehand()){
You("can't break %s with no free %s!", xname(obj), body_part(HAND));
return MOVE_CANCELLED;
}
if(yn("Shatter the gem?") == 'y'){
if(!Deadmagic && !Blind){
pline("The black flaw tears free, then expands to fill the world!");
if(base_casting_stat() == A_INT)
pline("The Weave frays and fails!");
}
//Don't bother doing math if the timeout is already infinite.
// It's not EASY to permanently break magic with these, but it is POSSIBLE!
if(Deadmagic < TIMEOUT_INF){
long increment = (long)(50 * pow(1.1,u.rift_count));
incr_itimeout(&Deadmagic, increment);
// Need to be careful with counts, since exponential math means that we can easily start overflowing stuff.
if(increment < TIMEOUT){
u.rift_count++;
}
}
useup(obj);
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
}
static int
use_vortex(struct obj *obj)
{
struct monst *mtmp = 0;
if(!freehand()){
You("can't break %s with no free %s!", xname(obj), body_part(HAND));
return MOVE_CANCELLED;
}
if(yn("Shatter the gem?") == 'y'){
if(!Catapsi && !Blind){
pline("The silvery-gray flaw spins free, then expands to fill the world!");
if(base_casting_stat() == A_CHA)
pline("Your mind fills with static!");
}
//Don't bother doing math if the timeout is already infinite.
// It's not EASY to permanently break magic with these, but it is POSSIBLE!
if(Catapsi < TIMEOUT_INF){
long increment = (long)(100 * pow(1.1,u.vortex_count));
incr_itimeout(&Catapsi, increment);
// Need to be careful with counts, since exponential math means that we can easily start overflowing stuff.
if(increment < TIMEOUT){
u.vortex_count++;
}
}
useup(obj);
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
}
void
pyramid_effects(struct obj *obj, int x, int y)
{
//Don't bother doing math if the timeout is already infinite.
// It's not EASY to permanently break magic with these, but it is POSSIBLE!
if(Misotheism < TIMEOUT_INF){
long increment = (long)(33 * pow(1.1,u.miso_count));
if(!Inhell && !Misotheism && u.ualign.type != A_VOID && !Role_if(PM_ANACHRONOUNBINDER)){
godlist[u.ualign.god].anger++;
gods_angry(u.ualign.god);
}
// Need to be careful with counts, since exponential math means that we can easily start overflowing stuff.
if(increment < TIMEOUT){
u.miso_count++;
}
if(obj->otyp == MISOTHEISTIC_PYRAMID){
if(!Blind && cansee(x, y)){
if(!DarksightOnly)
pline("An impossible darkness pours forth!");
else
pline("A mighty darkness issues forth!");
}
incr_itimeout(&HDarksight, increment);
incr_itimeout(&DarksightOnly, increment);
doredraw();
}
if(obj->otyp == MISOTHEISTIC_FRAGMENT){
if(!Shattering)
You_hear("a great fracturing sound!");
if(!Blind && cansee(x, y)){
if(!(u.specialSealsKnown&SEAL_NUDZIRATH) && !Role_if(PM_ANACHRONOUNBINDER)){
/*Note: this is intended to work for any PC, not just Binders */
pline("The shattered fragments form part of a seal.");
pline("In fact, you realize that all cracked and broken mirrors everywhere together are working towards writing this seal.");
pline("With that realization comes knowledge of the seal's final form!");
u.specialSealsKnown |= SEAL_NUDZIRATH;
}
}
incr_itimeout(&Shattering, increment);
}
if(!Misotheism && base_casting_stat() == A_WIS)
pline("You can no longer hear your god!");
incr_itimeout(&Misotheism, increment);
}
}
static int
use_pyramid(struct obj *obj)
{
struct monst *mtmp = 0;
if(!freehand()){
You("can't %s %s with no free %s!", obj->otyp == MISOTHEISTIC_PYRAMID ? "open" : "shatter",xname(obj), body_part(HAND));
return MOVE_CANCELLED;
}
if(yn(obj->otyp == MISOTHEISTIC_PYRAMID ? "Open the pyramid?" : "Further shatter the pyramid?") == 'y'){
pyramid_effects(obj, u.ux, u.uy);
useup(obj);
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
}
static int
use_dimensional_lock(struct obj *obj)
{
struct monst *mtmp = 0;
if(!Blind)
pline("The cerulean tree flashes and disapears.");
pline("The disk crumbles to dust!");
incr_itimeout(&DimensionalLock, 100L);
expel_summons();
useup(obj);
return MOVE_STANDARD;
}
static int
use_dilithium(struct obj *obj)
{
struct monst *mtmp = 0;
struct obj *dollobj = 0;
dollobj = getobj(chain_class, "install dilithium in");
if(!dollobj)
return MOVE_CANCELLED;
if(dollobj->otyp != BROKEN_ANDROID && dollobj->otyp != BROKEN_GYNOID){
pline("That's not a droid.");
return MOVE_CANCELLED;
}
mtmp = revive(dollobj, TRUE);
if(!mtmp){
pline("Nothing happens....");
return MOVE_CANCELLED;
}
mtmp->mhp = max(1, mtmp->m_lev);
pline("%s comes back online!", Monnam(mtmp));
useup(obj);
return MOVE_STANDARD;
}
static int
use_doll_tear(struct obj *obj)
{
struct monst *mtmp = 0;
if(yn("Give doll's tear to a monster?") == 'y'){
getdir("Which monster?");
if(u.dx || u.dy){
if(u.uswallow)
mtmp = u.ustuck;
else if(!isok(u.ux + u.dx, u.uy + u.dy)) return MOVE_CANCELLED;
else mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
if(!mtmp)
return MOVE_CANCELLED;
if(!is_dollable(mtmp->data)){
pline("That's not a doll.");
return MOVE_CANCELLED;
}
if(mtmp->m_insight_level){
pline("Nothing happens....");
return MOVE_CANCELLED;
}
mtmp->mvar_dollTypes = obj->ovar1_dollTypes;
mtmp->m_insight_level = obj->spe;
useup(obj);
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
} else {
struct obj *dollobj = 0;
dollobj = getobj(chain_class, "give the tear to");
if(!dollobj)
return MOVE_CANCELLED;
if(dollobj->otyp != BROKEN_ANDROID && dollobj->otyp != BROKEN_GYNOID && dollobj->otyp != LIFELESS_DOLL){
pline("That's not a doll.");
return MOVE_CANCELLED;
}
if(get_ox(dollobj, OX_EMON))
mtmp = get_mtraits(dollobj, FALSE);
else {
pline("Nothing happens....");
return MOVE_CANCELLED;
}
//I don't think this is possible given the above, but I'm feeling paranoid....
if(!mtmp){
pline("Nothing happens....");
return MOVE_CANCELLED;
}
dollobj->ovar1_insightlevel = (long)obj->spe;
mtmp->m_insight_level = (long)obj->spe;
mtmp->mvar_dollTypes = obj->ovar1_dollTypes;
useup(obj);
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
}
static int
use_doll(struct obj *obj)
{
int res = MOVE_CANCELLED;
struct monst *mtmp;
switch(obj->otyp){
case DOLL_OF_JUMPING:
if (jump(4)){
res = MOVE_STANDARD;
give_intrinsic(JUMPING, 100L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
}
break;
case DOLL_OF_FRIENDSHIP:
getdir((char *)0);
if(u.dx || u.dy){
if(u.uswallow)
mtmp = u.ustuck;
else if (!isok(u.ux + u.dx, u.uy + u.dy)) break;
else mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
pline("The doll sings sweetly.");
if(mtmp && resist_song(mtmp, SNG_TAME, obj) >= 0){
if (mtmp->mtame){
if(!get_mx(mtmp, MX_EDOG) || (EDOG(mtmp)->friend))
break;
if(mtmp->mtame < 16) mtmp->mtame++;
} else {
xchar waspeaceful = mtmp->mpeaceful;
mtmp = tamedog(mtmp, obj);
if(mtmp){
if (canseemon(mtmp) && flags.verbose && !mtmp->msleeping)
pline("%s seems to like the doll's song.", Monnam(mtmp));
mtmp->mtame = 9;
EDOG(mtmp)->waspeaceful = TRUE;
if(!waspeaceful || mtmp->mpeacetime){ /*Should it become untame, remain tame peaceful for a short period of time*/
mtmp->mpeacetime = max(mtmp->mpeacetime, 90);
}
}
}
res = MOVE_STANDARD;
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
}
}
break;
case DOLL_OF_CHASTITY:
res = MOVE_STANDARD;
pline("You feel chaste.");
give_intrinsic(CHASTITY, 100L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_CLEAVING:
res = MOVE_STANDARD;
if(!Blind)
pline("The doll swings its %s in wide arcs.", rn2(2) ? "greatsword" : "greataxe");
give_intrinsic(CLEAVING, 100L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_SATIATION:
if(satiate_uhunger()){
res = MOVE_STANDARD;
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
}
break;
case DOLL_OF_GOOD_HEALTH:
if(Slimed){
Slimed = 0L;
flags.botl = 1;
}
healup(0, 0, TRUE, FALSE);
if (Stoned) fix_petrification();
if (Golded) fix_petrification();
res = MOVE_STANDARD;
pline("You feel very healthy.");
give_intrinsic(GOOD_HEALTH, 100L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_FULL_HEALING:
res = MOVE_STANDARD;
if((!Upolyd && u.uhp < u.uhpmax) ||
(Upolyd && u.mh < u.mhmax)
)
pline("Your wounds begin rapidly knitting shut.");
give_intrinsic(RAPID_HEALING, 5L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_DESTRUCTION:
res = MOVE_STANDARD;
if(!Blind)
pline("The many-armed doll begins dancing!");
give_intrinsic(DESTRUCTION, 64L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_MEMORY:
if(doreinforce_spell()){
res = MOVE_STANDARD;
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
}
break;
case DOLL_OF_BINDING:
if(doreinforce_binding()){
res = MOVE_STANDARD;
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
}
break;
case DOLL_OF_PRESERVATION:
res = MOVE_STANDARD;
if(!Blind)
pline("The doll opens its umbrella, and a rubbery film forms around your body!");
give_intrinsic(PRESERVATION, 1000L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_QUICK_DRAWING:
res = MOVE_STANDARD;
if(!Blind)
pline("The doll draws a wand with blinding speed!");
give_intrinsic(QUICK_DRAW, 100L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_WAND_CHARGING:
if(dowand_refresh()){
res = MOVE_STANDARD;
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
}
break;
case DOLL_OF_STEALING:
getdir((char *)0);
if(u.dx || u.dy){
if(u.uswallow)
mtmp = u.ustuck;
else if (!isok(u.ux + u.dx, u.uy + u.dy)) break;
else mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
if(mtmp){
struct obj *otmp;
long long unwornmask;
//Note: unlike normal theft, you are never petrified by a stolen item because the doll is doing it.
if(!Blind) pline("The black-clad doll steals %s possessions.", s_suffix(mon_nam(mtmp)));
while ((otmp = mtmp->minvent) != 0) {
/* take the object away from the monster */
obj_extract_self(otmp);
if ((unwornmask = otmp->owornmask) != 0L) {
mtmp->misc_worn_check &= ~unwornmask;
if (otmp->owornmask & W_WEP) {
setmnotwielded(mtmp,otmp);
MON_NOWEP(mtmp);
}
if (otmp->owornmask & W_SWAPWEP){
setmnotwielded(mtmp,otmp);
MON_NOSWEP(mtmp);
}
otmp->owornmask = 0L;
}
update_mon_intrinsics(mtmp, otmp, FALSE, FALSE);
if(!Blind) pline("The doll steals %s %s and drops it to the %s.",
s_suffix(mon_nam(mtmp)), xname(otmp), surface(u.ux, u.uy));
dropy(otmp);
/* more take-away handling, after theft message */
if (unwornmask & W_WEP || unwornmask & W_SWAPWEP) { /* stole wielded weapon */
possibly_unwield(mtmp, FALSE);
} else if (unwornmask & W_ARMG) { /* stole worn gloves */
mselftouch(mtmp, (const char *)0, TRUE);
if (mtmp->mhp <= 0) /* it's now a statue */
break; /* can't continue stealing */
}
}
#ifndef GOLDOBJ
if (mtmp->mgold){
struct obj *mongold = mksobj(GOLD_PIECE, MKOBJ_NOINIT);
mongold->quan = mtmp->mgold;
mongold->owt = weight(mongold);
mtmp->mgold = 0;
if(!Blind) pline("The doll steals %s gold and drops it to the %s.", s_suffix(mon_nam(mtmp)), surface(u.ux, u.uy));
dropy(mongold);
}
#else
{
struct obj *mongold = findgold(mtmp->minvent);
if (mongold) {
obj_extract_self(mongold);
if(!Blind) pline("The doll steals %s gold and drops it to the %s.", s_suffix(mon_nam(mtmp)), surface(u.ux, u.uy));
dropy(mongold);
}
}
#endif
res = MOVE_STANDARD;
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
setmangry(mtmp);
}
}
break;
case DOLL_OF_MOLLIFICATION:
if(godlist[u.ualign.god].anger) {
if(!Blind)
pline("The %s says a prayer.", OBJ_DESCR(objects[obj->otyp]));
pline("%s seems %s.", u_gname(),
Hallucination ? "groovy" : "mollified");
godlist[u.ualign.god].anger = 0;
if ((int)u.uluck < 0) u.uluck = 0;
u.reconciled = REC_MOL;
res = MOVE_STANDARD;
if(!Blind)
pline("The little doll vanishes in a flash of moonlight.");
else pline("The little doll vanishes.");
useup(obj);
}
break;
case DOLL_OF_CLEAR_THINKING:
res = MOVE_STANDARD;
pline("The doll takes up your mental burdens!");
give_intrinsic(CLEAR_THOUGHTS, 100L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
case DOLL_OF_MIND_BLASTING:
res = MOVE_STANDARD;
give_intrinsic(MIND_BLASTS, 8L);
if(!Blind)
pline("The %s vanishes in a flash of moonlight.", OBJ_DESCR(objects[obj->otyp]));
else pline("The little doll vanishes.");
useup(obj);
break;
default:
break;
}
return res;
}
boolean
wish_imperial(struct obj *obj)
{
struct monst * mtmp;
boolean madewish = FALSE;
if (DimensionalLock || !(mtmp = makemon(&mons[flags.female ? PM_STAR_EMPRESS : PM_STAR_EMPEROR], u.ux, u.uy, MM_ADJACENTOK|MM_NOCOUNTBIRTH|NO_MINVENT))){
pline1(nothing_happens);
}
else
{
if (!Blind) {
pline("%s descends in a rain of stars!", Amonnam(mtmp));
pline("%s speaks.", Monnam(mtmp));
}
else {
You("smell clean air.");
pline("%s speaks.", Something);
}
verbalize("I will grant one wish!");
int artwishes = u.uconduct.wisharti;
if (makewish(WISH_VERBOSE | (!(u.uevent.uconstellation & ARTWISH_SPENT) ? WISH_ARTALLOW : 0 ))) {
obj->spe--;
madewish = TRUE;
}
if (u.uconduct.wisharti > artwishes) {
/* made artifact wish */
u.uevent.uconstellation |= ARTWISH_SPENT;
}
mongone(mtmp);
if (!objects[RIN_WISHES].oc_name_known) {
makeknown(RIN_WISHES);
more_experienced(0, 10);
}
}
return madewish;
}
boolean
wish_standard(struct obj *obj)
{
struct monst * mtmp;
struct monst * mtmp2 = (struct monst*)0;
struct monst * mtmp3 = (struct monst*)0;
boolean madewish = FALSE;
if (!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy, NO_MM_FLAGS))){
pline1(nothing_happens);
}
else
{
if (!DimensionalLock) {
if ((u.uevent.utook_castle & ARTWISH_EARNED) && !(u.uevent.utook_castle & ARTWISH_SPENT))
mtmp2 = makemon(&mons[PM_PSYCHOPOMP], u.ux, u.uy, NO_MM_FLAGS);
if ((u.uevent.uunknowngod & ARTWISH_EARNED) && !(u.uevent.uunknowngod & ARTWISH_SPENT))
mtmp3 = makemon(&mons[PM_PRIEST_OF_AN_UNKNOWN_GOD], u.ux, u.uy, NO_MM_FLAGS);
}
if (!Blind) {
pline("%s appears in a cloud of smoke!", Amonnam(mtmp));
if (mtmp2 || mtmp3)
pline("It is accompanied by %s%s%s.",
mtmp2 ? a_monnam(mtmp2) : "",
(mtmp2 && mtmp3) ? " and " : "",
mtmp3 ? a_monnam(mtmp3) : "");
pline("%s speaks.", Monnam(mtmp));
}
else {
You("smell acrid fumes.");
pline("%s speaks.", Something);
}
verbalize("I am the djinni of the ring. I will grant one wish!");
int artwishes = u.uconduct.wisharti;
if (makewish(WISH_VERBOSE | (DimensionalLock ? 0 :allow_artwish()))) {
obj->spe--;
madewish = TRUE;
}
if (u.uconduct.wisharti > artwishes) {
/* made artifact wish */
if (mtmp2) {
pline("You feel %s presence fade.", s_suffix(mon_nam(mtmp2)));
mongone(mtmp2);
mtmp2 = (struct monst*) 0;
u.uevent.utook_castle |= ARTWISH_SPENT;
}
else if (mtmp3) {
pline("You feel %s presence fade.", s_suffix(mon_nam(mtmp3)));
mongone(mtmp3);
mtmp3 = (struct monst*) 0;
u.uevent.uunknowngod |= ARTWISH_SPENT;
}
}
pline("The djinni%s disappears with a puff of smoke.", (mtmp2 || mtmp3) ? " and their entourage" : "");
mongone(mtmp);
if (mtmp2) mongone(mtmp2);
if (mtmp3) mongone(mtmp3);
if (!objects[RIN_WISHES].oc_name_known) {
makeknown(RIN_WISHES);
more_experienced(0, 10);
}
}
return madewish;
}
boolean
use_ring_of_wishes(struct obj *obj)
{
boolean madewish = FALSE;
if (obj->otyp != RIN_WISHES)
{
impossible("object other than ring of wishes passed to use_ring_of_wishes");
return FALSE;
}
if (obj->cursed || (Luck + rn2(5) < 0)){ // to be less cruel, it doesn't use up a charge
pline1(nothing_happens);
return FALSE;
}
if (!(obj->owornmask & W_RING)) {
if (objects[RIN_WISHES].oc_name_known)
You_feel("that you should be wearing %s.", the(xname(obj)));
else
pline1(nothing_happens);
return FALSE;
}
if (obj->spe > 0)
{
if(obj->oartifact == ART_STAR_EMPEROR_S_RING)
madewish = wish_imperial(obj);
else
madewish = wish_standard(obj);
}
else
{
pline1(nothing_happens);
}
return madewish;
}
#define SUMMON_DJINNI 1
#define SUMMON_SERVANT 2
#define SUMMON_DEMON_LORD 3
#define MISINPUT 4
int
do_candle_menu(void)
{
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Summon Djinni");
any.a_int = SUMMON_DJINNI; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet + 1) : 'A';
Sprintf(buf, "Summon Servant");
any.a_int = SUMMON_SERVANT; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet + 1) : 'A';
Sprintf(buf, "Summon Demon Lord");
any.a_int = SUMMON_DEMON_LORD; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet + 1) : 'A';
Sprintf(buf, "Abort Summoning");
any.a_int = MISINPUT; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet + 1) : 'A';
end_menu(tmpwin, "What creature do you wish to summon?");
how = PICK_ONE;
do{
n = select_menu(tmpwin, how, &selected);
} while (n <= 0);
destroy_nhwindow(tmpwin);
if(n > 0){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
int
do_demon_lord_summon_menu(void)
{
winid tmpwin;
int n, how, i;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
for (i = 0; i >= LOW_PM && i<SPECIAL_PM; i++)
{
if (is_dlord(&mons[i]) && type_is_pname(&mons[i]) && !(mvitals[i].mvflags & G_EXTINCT))
{
Sprintf(buf, "%s", mons[i].mname);
any.a_int = i; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet + 1) : 'A';
}
}
if (incntlet == 'a'){
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "There's nobody left to answer your summons!", MENU_UNSELECTED);
}
end_menu(tmpwin, "Which demon do you wish to summon?");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n > 0){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
boolean
use_candle_of_invocation(struct obj *obj)
{
int choice = 0;
boolean consumed = FALSE;
struct monst * mtmp = (struct monst *)0;
if (obj->otyp != CANDLE_OF_INVOCATION)
{
impossible("object other than candle of invocation passed to use_candle_of_invocation");
return FALSE;
}
if (!obj->lamplit || DimensionalLock || Is_nowhere(&u.uz)) {
pline1(nothing_happens);
return FALSE;
}
pline("The %s flares, and a planar gate opens!", xname(obj));
do{
choice = do_candle_menu();
switch (choice)
{
case SUMMON_DJINNI:
if (!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy, NO_MM_FLAGS))){
pline("Nothing responds to the call.");
consumed = FALSE;
break;
}
else {
struct monst *mtmp2 = (struct monst*)0;
struct monst *mtmp3 = (struct monst*)0;
if ((u.uevent.utook_castle & ARTWISH_EARNED) && !(u.uevent.utook_castle & ARTWISH_SPENT))
mtmp2 = makemon(&mons[PM_PSYCHOPOMP], u.ux, u.uy, NO_MM_FLAGS);
if ((u.uevent.uunknowngod & ARTWISH_EARNED) && !(u.uevent.uunknowngod & ARTWISH_SPENT))
mtmp3 = makemon(&mons[PM_PRIEST_OF_AN_UNKNOWN_GOD], u.ux, u.uy, NO_MM_FLAGS);
if (!Blind) {
pline("%s passes through the gate in a cloud of smoke!", Amonnam(mtmp));
if (mtmp2 || mtmp3)
pline("It is accompanied by %s%s%s.",
mtmp2 ? a_monnam(mtmp2) : "",
(mtmp2 && mtmp3) ? " and " : "",
mtmp3 ? a_monnam(mtmp3) : "");
pline("%s speaks.", Monnam(mtmp));
}
else {
You("smell acrid fumes.");
pline("%s speaks.", Something);
}
verbalize("You have summoned me. I will grant one wish!");
int artwishes = u.uconduct.wisharti;
consumed = makewish(allow_artwish() | WISH_VERBOSE);
if (u.uconduct.wisharti > artwishes) {
/* made artifact wish */
if (mtmp2) {
pline("You feel %s presence fade.", s_suffix(mon_nam(mtmp2)));
mongone(mtmp2);
mtmp2 = (struct monst*) 0;
u.uevent.utook_castle |= ARTWISH_SPENT;
}
else if (mtmp3) {
pline("You feel %s presence fade.", s_suffix(mon_nam(mtmp3)));
mongone(mtmp3);
mtmp3 = (struct monst*) 0;
u.uevent.uunknowngod |= ARTWISH_SPENT;
}
}
pline("The djinni%s disappears with a puff of smoke.", (mtmp2 || mtmp3) ? " and their entourage" : "");
mongone(mtmp);
if (mtmp2) mongone(mtmp2);
if (mtmp3) mongone(mtmp3);
if (!consumed){
pline("Perhaps try summoning something else?");
}
}
break;
case SUMMON_SERVANT:{
long futurewishflag = Role_if(PM_TOURIST) ? 0 : MG_FUTURE_WISH;
mtmp = create_particular(u.ux, u.uy, MT_DOMESTIC, 0, FALSE, MA_MINION | MA_DEMON | MA_FEY | MA_PRIMORDIAL, MG_NOWISH | MG_NOTAME | futurewishflag, G_UNIQ, (char *)0);
if (!mtmp) {
pline("Perhaps try summoning something else?");
consumed = FALSE;
}
else {
pline("The gate closes as %s passes through.", a_monnam(mtmp));
consumed = TRUE;
}
break;
}
case SUMMON_DEMON_LORD:
choice = do_demon_lord_summon_menu();
if (!choice){
// the player didn't choose an option
consumed = FALSE;
break;
}
if (!(mtmp = makemon(&mons[choice], u.ux, u.uy, NO_MM_FLAGS))){
// the demon was already generated
pline("Nothing responds to the call.");
consumed = FALSE;
break;
}
else {
if (!Blind) {
pline("%s passes through the gate.", Monnam(mtmp));
}
else {
You_feel("a hostile presence.");
}
mtmp->mpeaceful = 0;
consumed = TRUE;
}
break;
case MISINPUT:
return FALSE;
default:
consumed = FALSE;
break;
}
} while (!consumed);
pline("The %s is consumed.", xname(obj));
useupall(obj);
if (!objects[CANDLE_OF_INVOCATION].oc_name_known) {
makeknown(CANDLE_OF_INVOCATION);
more_experienced(0, 10);
}
return TRUE;
}
#undef SUMMON_DJINNI
#undef SUMMON_SERVANT
#undef SUMMON_DEMON_LORD
#undef MISINPUT
#define BY_OBJECT ((struct monst *)0)
static int
do_break_wand(struct obj *obj)
{
static const char nothing_else_happens[] = "But nothing else happens...";
register int i, x, y;
register struct monst *mon;
int dmg, damage;
boolean affects_objects, is_fragile;
boolean shop_damage = FALSE;
int expltype = EXPL_MAGICAL;
char confirm[QBUFSZ], the_wand[BUFSZ], buf[BUFSZ];
Strcpy(the_wand, yname(obj));
Snprintf(confirm, QBUFSZ, "Are you really sure you want to break %s?",
safe_qbuf("", sizeof("Are you really sure you want to break ?"),
the_wand, ysimple_name(obj), "the wand"));
if (yesno(confirm, iflags.paranoid_wand_break) != 'y') return MOVE_CANCELLED;
is_fragile = (!strcmp(OBJ_DESCR(objects[obj->otyp]), "balsa"));
if (nolimbs(youracedata)) {
You_cant("break %s without limbs!", the_wand);
return MOVE_CANCELLED;
} else if (obj->oartifact || ACURR(A_STR) < (is_fragile ? 5 : 10)) {
You("don't have the strength to break %s!", the_wand);
return MOVE_CANCELLED;
}
pline("Raising %s high above your %s, you %s it in two!",
the_wand, body_part(HEAD), is_fragile ? "snap" : "break");
/* [ALI] Do this first so that wand is removed from bill. Otherwise,
* the freeinv() below also hides it from setpaid() which causes problems.
*/
if (obj->unpaid) {
check_unpaid(obj); /* Extra charge for use */
bill_dummy_object(obj);
}
if(u.sealsActive&SEAL_ASTAROTH) unbind(SEAL_ASTAROTH, TRUE);
current_wand = obj; /* destroy_item might reset this */
freeinv(obj); /* hide it from destroy_item instead... */
setnotworn(obj); /* so we need to do this ourselves */
if (obj->spe <= 0) {
pline("%s", nothing_else_happens);
goto discard_broken_wand;
}
obj->ox = u.ux;
obj->oy = u.uy;
dmg = obj->spe * 4;
affects_objects = FALSE;
switch (obj->otyp) {
case WAN_NOTHING:
pline("Suddenly, and without warning, nothing happens.");
goto discard_broken_wand;
case WAN_WISHING:
case WAN_LOCKING:
case WAN_PROBING:
case WAN_ENLIGHTENMENT:
case WAN_SECRET_DOOR_DETECTION:
pline("%s", nothing_else_happens);
goto discard_broken_wand;
case WAN_OPENING:
/* make trap door if you broke a wand of opening */
if ((obj->spe > 2) && rn2(obj->spe - 2) && !u.uswallow &&
!On_stairs(u.ux, u.uy) && (!IS_FURNITURE(levl[u.ux][u.uy].typ) &&
!IS_ROCK(levl[u.ux][u.uy].typ) && !closed_door(u.ux, u.uy) &&
!t_at(u.ux, u.uy) && Can_dig_down(&u.uz))) {
struct trap *ttmp;
ttmp = maketrap(u.ux, u.uy, TRAPDOOR);
if (ttmp) {
ttmp->madeby_u = 1;
ttmp->tseen = 1;
newsym(u.ux, u.uy);
if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
add_damage(u.ux, u.uy, 0L);
}
}
}
goto discard_broken_wand;
case WAN_DEATH:
case WAN_LIGHTNING:
dmg *= 4;
goto wanexpl;
case WAN_FIRE:
expltype = EXPL_FIERY;
case WAN_COLD:
if (expltype == EXPL_MAGICAL) expltype = EXPL_FROSTY;
dmg *= 2;
case WAN_MAGIC_MISSILE:
wanexpl:
explode(u.ux, u.uy,
wand_adtype(obj->otyp), WAND_CLASS, dmg, expltype, 1);
makeknown(obj->otyp); /* explode described the effect */
/* make magic trap if you broke a wand of magic missile */
if ((obj->spe > 2) && rn2(obj->spe - 2) && !u.uswallow &&
!On_stairs(u.ux, u.uy) && (!IS_FURNITURE(levl[u.ux][u.uy].typ) &&
!IS_ROCK(levl[u.ux][u.uy].typ) &&
!closed_door(u.ux, u.uy) && !t_at(u.ux, u.uy))) {
struct trap *ttmp;
ttmp = maketrap(u.ux, u.uy, MAGIC_TRAP);
if (ttmp) {
ttmp->madeby_u = 1;
ttmp->tseen = 1;
newsym(u.ux, u.uy);
if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
add_damage(u.ux, u.uy, 0L);
}
}
}
goto discard_broken_wand;
case WAN_STRIKING:
/* we want this before the explosion instead of at the very end */
pline("A wall of force smashes down around you!");
dmg = d(1 + obj->spe,6); /* normally 2d12 */
break;
case WAN_TELEPORTATION:
/* WAC make tele trap if you broke a wand of teleport */
/* But make sure the spot is valid! */
if ((obj->spe > 2) && rn2(obj->spe - 2) && !notel_level() &&
!u.uswallow && !On_stairs(u.ux, u.uy) && (!IS_FURNITURE(levl[u.ux][u.uy].typ) &&
!IS_ROCK(levl[u.ux][u.uy].typ) &&
!closed_door(u.ux, u.uy) && !t_at(u.ux, u.uy))) {
struct trap *ttmp;
ttmp = maketrap(u.ux, u.uy, TELEP_TRAP);
if (ttmp) {
ttmp->madeby_u = 1;
ttmp->tseen = 1;
newsym(u.ux, u.uy); /* if our hero happens to be invisible */
if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
/* shopkeeper will remove it */
add_damage(u.ux, u.uy, 0L);
}
}
}
affects_objects = TRUE;
break;
case WAN_POLYMORPH:
/* make poly trap if you broke a wand of polymorph */
if ((obj->spe > 2) && rn2(obj->spe - 2) && !u.uswallow &&
!On_stairs(u.ux, u.uy) && (!IS_FURNITURE(levl[u.ux][u.uy].typ) &&
!IS_ROCK(levl[u.ux][u.uy].typ) &&
!closed_door(u.ux, u.uy) && !t_at(u.ux, u.uy))) {
struct trap *ttmp;
ttmp = maketrap(u.ux, u.uy, POLY_TRAP);
if (ttmp) {
ttmp->madeby_u = 1;
ttmp->tseen = 1;
newsym(u.ux, u.uy);
if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
add_damage(u.ux, u.uy, 0L);
}
}
}
affects_objects = TRUE;
break;
case WAN_SLEEP:
/* make sleeping gas trap if you broke a wand of sleep */
if ((obj->spe > 2) && rn2(obj->spe - 2) && !u.uswallow &&
!On_stairs(u.ux, u.uy) && (!IS_FURNITURE(levl[u.ux][u.uy].typ) &&
!IS_ROCK(levl[u.ux][u.uy].typ) &&
!closed_door(u.ux, u.uy) && !t_at(u.ux, u.uy))) {
struct trap *ttmp;
ttmp = maketrap(u.ux, u.uy, SLP_GAS_TRAP);
if (ttmp) {
ttmp->madeby_u = 1;
ttmp->tseen = 1;
newsym(u.ux, u.uy);
if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
add_damage(u.ux, u.uy, 0L);
}
}
}
break;
case WAN_CANCELLATION:
/* make anti-magic trap if you broke a wand of cancellation */
if ((obj->spe > 2) && rn2(obj->spe - 2) && !u.uswallow &&
!On_stairs(u.ux, u.uy) && (!IS_FURNITURE(levl[u.ux][u.uy].typ) &&
!IS_ROCK(levl[u.ux][u.uy].typ) &&
!closed_door(u.ux, u.uy) && !t_at(u.ux, u.uy))) {
struct trap *ttmp;
ttmp = maketrap(u.ux, u.uy, ANTI_MAGIC);
if (ttmp) {
ttmp->madeby_u = 1;
ttmp->tseen = 1;
newsym(u.ux, u.uy);
if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
add_damage(u.ux, u.uy, 0L);
}
}
}
affects_objects = TRUE;
break;
case WAN_UNDEAD_TURNING:
affects_objects = TRUE;
break;
default:
break;
}
/* magical explosion and its visual effect occur before specific effects */
explode(obj->ox, obj->oy, AD_MAGM, WAND_CLASS, rnd(dmg), EXPL_MAGICAL, 1);
/* this makes it hit us last, so that we can see the action first */
for (i = 0; i <= 8; i++) {
bhitpos.x = x = obj->ox + xdir[i];
bhitpos.y = y = obj->oy + ydir[i];
if (!isok(x,y)) continue;
if (obj->otyp == WAN_DIGGING) {
if(dig_check(BY_OBJECT, FALSE, x, y)) {
if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) {
/* normally, pits and holes don't anger guards, but they
* do if it's a wall or door that's being dug */
watch_dig((struct monst *)0, x, y, TRUE);
if (*in_rooms(x,y,SHOPBASE)) shop_damage = TRUE;
}
if(IS_GRAVE(levl[x][y].typ)){
digactualhole(x, y, BY_OBJECT, PIT, FALSE, TRUE);
dig_up_grave(x,y);
} else if(IS_SEAL(levl[x][y].typ)){
// digactualhole(x, y, BY_OBJECT, PIT, FALSE, TRUE);
break_seal(x,y);
} else{
digactualhole(x, y, BY_OBJECT,
(rn2(obj->spe) < 3 || !Can_dig_down(&u.uz)) ?
PIT : HOLE, FALSE, TRUE);
}
}
continue;
} else if(obj->otyp == WAN_CREATE_MONSTER) {
/* u.ux,u.uy creates it near you--x,y might create it in rock */
if(!DimensionalLock)
(void) makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS);
continue;
} else {
if (x == u.ux && y == u.uy) {
/* teleport objects first to avoid race with tele control and
autopickup. Other wand/object effects handled after
possible wand damage is assessed */
if (obj->otyp == WAN_TELEPORTATION &&
affects_objects && level.objects[x][y]) {
(void) bhitpile(obj, bhito, x, y);
if (flags.botl) bot(); /* potion effects */
}
damage = zapyourself(obj, FALSE);
if (damage) {
Sprintf(buf, "killed %sself by breaking a wand", uhim());
losehp(damage, buf, NO_KILLER_PREFIX);
}
if (flags.botl) bot(); /* blindness */
} else if ((mon = m_at(x, y)) != 0) {
(void) bhitm(mon, obj);
/* if (flags.botl) bot(); */
}
if (affects_objects && level.objects[x][y]) {
(void) bhitpile(obj, bhito, x, y);
if (flags.botl) bot(); /* potion effects */
}
}
}
/* Note: if player fell thru, this call is a no-op.
Damage is handled in digactualhole in that case */
if (shop_damage) pay_for_damage("dig into", FALSE);
if (obj->otyp == WAN_LIGHT){
litroom(TRUE, obj); /* only needs to be done once */
if(u.sealsActive&SEAL_TENEBROUS) unbind(SEAL_TENEBROUS,TRUE);
}
else if (obj->otyp == WAN_DARKNESS){
litroom(FALSE, obj); /* only needs to be done once */
}
discard_broken_wand:
obj = current_wand; /* [see dozap() and destroy_item()] */
current_wand = 0;
if (obj)
delobj(obj);
nomul(0, NULL);
return MOVE_STANDARD;
}
static boolean
uhave_graystone(void)
{
register struct obj *otmp;
for(otmp = invent; otmp; otmp = otmp->nobj)
if(is_graystone(otmp))
return TRUE;
return FALSE;
}
static int
do_flip_coin(struct obj *obj)
{
#ifndef GOLDOBJ
u.ugold += obj->quan;
dealloc_obj(obj);
#endif
if (nohands(youracedata)) {
pline("And how would you flip the coin without hands?");
return MOVE_CANCELLED;
} else if (!freehand()) {
You("need at least one free %s.", body_part(HAND));
return MOVE_CANCELLED;
} else if (Underwater) {
pline("This coin wasn't designed to be flipped underwater.");
return MOVE_CANCELLED;
}
You("flip %s coin.",
#ifndef GOLDOBJ
(u.ugold > 1)
#else
(obj->quan > 1)
#endif
? "a" : "the");
if (!Fumbling && !Glib && !Blind &&
((ACURR(A_DEX) + Luck) > 0) && rn2((ACURR(A_DEX) + Luck))) {
xchar ht = rn2(2);
pline("%s.", ht ? "Heads" : "Tails");
if (Hallucination && ht && !rn2(8))
pline("Oh my, it %s at you!", rn2(2) ? "grins" : "winks");
} else {
struct obj *gold;
You("try to catch the coin but it slips from your %s.",
makeplural(body_part(HAND)));
#ifndef GOLDOBJ
gold = mkgoldobj(1);
#else
if (obj->quan > 1) gold = splitobj(obj, 1L);
else gold = obj;
#endif
dropx(gold);
}
return MOVE_STANDARD;
}
static void
soul_crush_consequence(struct obj *obj)
{
if (obj->blessed) {
You("crush the %s in your %s.", obj->dknown ? OBJ_DESCR(objects[obj->otyp]) : "coin", body_part(HAND));
You("release the soul!");
u.ublesscnt = 0;
if(rn2(100)){
pline("...you feel the soul sink towards Gehennom.");
/* Points for trying */
u.ualign.sins = max(u.ualign.sins-1, 0);
adjalign(7);
if(godlist[u.ualign.god].anger) {
godlist[u.ualign.god].anger--;
if (godlist[u.ualign.god].anger) {
pline("%s seems %s.", u_gname(),
Hallucination ? "groovy" : "slightly mollified");
if ((int)u.uluck < 0) change_luck(1);
} else {
pline("%s seems %s.", u_gname(), Hallucination ?
"cosmic (not a new fact)" : "mollified");
if ((int)u.uluck < 0) u.uluck = 0;
u.reconciled = REC_MOL;
}
}
}
else {
/* Freed someone who wasn't supposed to be there! */
u.ualign.sins = max(u.ualign.sins-7, 0);
u.ualign.record = ALIGNLIM;
if(godlist[u.ualign.god].anger) {
godlist[u.ualign.god].anger = 0;
pline("%s seems %s.", u_gname(), Hallucination ?
"cosmic (not a new fact)" : "mollified");
if ((int)u.uluck < 0) u.uluck = 0;
u.reconciled = REC_MOL;
}
}
}
else if (!obj->cursed) {
u.ualign.sins++;
if(!rn2(100)){
You("feel the soul fly free!");
adjalign(1);
if ((int)u.uluck < 0) change_luck(1);
}
}
else {
u.ualign.sins += 9;
adjalign(-99);
if(!rn2(100)){
You("feel the soul scream as it sinks towards Gehennom under the weight of the curse!");
/* Just sent someone back who shouldn't be there :( */
gods_upset(u.ualign.god);
}
}
}
static int
do_soul_coin(struct obj *obj)
{
char coinbuff[50] = {0};
struct monst *mtmp = (struct monst *)0;
struct obj *otmp;
int x, y;
int tmp;
coord cc = {u.ux, u.uy};
if(!freehand()){
You("can't crush %s with no free %s!", the(xname(obj)), body_part(HAND));
return MOVE_CANCELLED;
}
/* most wages need a target, or else they abort.
* Blessed wages all have the same non-targeted effect */
if (!obj->blessed &&
obj->otyp != WAGE_OF_SLOTH &&
obj->otyp != WAGE_OF_LUST
){
boolean needs_mon = (obj->otyp != WAGE_OF_GREED);
boolean needs_space = (obj->otyp == WAGE_OF_GREED);
/* choose target */
if (needs_mon)
pline("Pick a creature to target.");
else
pline("Pick a location to target.");
if(getpos(&cc, TRUE, "the target") < 0) return MOVE_CANCELLED;
x = cc.x;
y = cc.y;
if(distmin(u.ux, u.uy, x, y) > BOLT_LIM || !clear_path(u.ux, u.uy, x, y)){
pline("It can't reach there!");
return MOVE_CANCELLED;
}
if(needs_space && (closed_door(x, y) || IS_ROCK(levl[x][y].typ))){
You("can't use that there.");
return MOVE_CANCELLED;
}
mtmp = m_u_at(x, y);
if(needs_mon && (!mtmp || DEADMONSTER(mtmp))){
You("see no target there!");
return MOVE_CANCELLED;
}
if(mtmp == &youmonst){
Sprintf(coinbuff, "Use the %s on yourself?", obj->dknown ? OBJ_DESCR(objects[obj->otyp]) : "coin");
if(yn(coinbuff) == 'n')
return MOVE_CANCELLED;
}
else if(needs_mon && !canspotmon(mtmp)){
You("see no target there!");
return MOVE_CANCELLED;
}
}
/* did not abort during targeting; activate */
You("crush the %s in your %s.", obj->dknown ? OBJ_DESCR(objects[obj->otyp]) : "coin", body_part(HAND));
/* main effect -- does not happen with blessed wages. */
if (!obj->blessed) {
switch(obj->otyp){
case WAGE_OF_SLOTH:
tmp = obj->cursed ? 4 : 2;
You("blur with stolen time!");
HTimeStop += (long)tmp;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
if(is_uvuudaum(mtmp->data) && !DEADMONSTER(mtmp)){
mtmp->movement += NORMAL_SPEED*tmp;
}
}
break;
case WAGE_OF_LUST:
tmp = obj->cursed ? 22 : 9;
if(!BlowingWinds){
pline("Hurricane-force winds surround you!");
}
else {
pline("The hurricane-force winds intensify!");
}
HBlowingWinds += (long)tmp;
break;
case WAGE_OF_GLUTTONY:
if(inediate(mtmp->data)){
pline("%s %s unbothered.",
(mtmp == &youmonst) ? "You" : Monnam(mtmp),
(mtmp == &youmonst) ? "are" : "is");
}
else {
tmp = obj->cursed ? 2000 : 1000;
if(mtmp == &youmonst){
morehungry(tmp*get_uhungersizemod());
}
else {
if(mtmp->mtame && get_mx(mtmp, MX_EDOG)){
EDOG(mtmp)->hungrytime = max(EDOG(mtmp)->hungrytime - tmp, monstermoves - (500 + 250*obj->cursed));
}
else {
if(obj->cursed){
mtmp->mhp -= min(333, mtmp->mhpmax);
}
else {
mtmp->mhp -= max(33, min(99, mtmp->mhpmax/2));
}
if(mtmp->mhp <= 0){
pline("%s starves.", Monnam(mtmp));
mondied(mtmp);
}
else {
pline("%s is confused from hunger.", Monnam(mtmp));
mtmp->mconf = 1;
}
}
}
}
break;
case WAGE_OF_GREED:
otmp = mksobj(MASS_OF_STUFF, MKOBJ_NOINIT);
if (!otmp) break; /* Shouldn't happen */
curse(otmp);
/* Note, blessed was handled above. */
if(obj->cursed){
projectile(&youmonst, otmp, (void *)0, HMON_PROJECTILE|HMON_FIRED, u.ux, u.uy, (x-u.ux), (y-u.uy), 0, 1, FALSE, FALSE, FALSE);
}
else if(mtmp){
int dmg;
boolean youdef = mtmp == &youmonst;
if(youdef)
pline("%s drops out of nowhere and hits you!", An(xname(otmp)));
else if (cansee(mtmp->mx, mtmp->my)) {
pline("%s is hit by %s!", Monnam(mtmp),
doname(otmp));
if (mtmp->minvis && !canspotmon(mtmp))
map_invisible(mtmp->mx, mtmp->my);
}
dmg = dmgval(otmp, mtmp, 0, &youmonst);
struct obj *helmet = youdef ? uarmh : which_armor(mtmp, W_ARMH);
if (helmet) {
if(is_hard(helmet)) {
if(youdef)
pline("Fortunately, you are wearing a hard helmet.");
else if (canspotmon(mtmp))
pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp));
else if (flags.soundok)
You_hear("a clanging sound.");
if (dmg > 2) dmg = 2;
}
else if (flags.verbose) {
if(youdef)
Your("%s does not protect you.",
xname(helmet));
else if(canspotmon(mtmp))
pline("%s's %s does not protect %s.",
Monnam(mtmp), xname(helmet),
mhim(mtmp));
}
}
if (!flooreffects(otmp, x, y, "fall")) {
place_object(otmp, x, y);
stackobj(otmp);
newsym(x, y);
}
dmg = reduce_dmg(mtmp,dmg,TRUE,FALSE);
if(youdef)
losehp(dmg, "mass of falling stuff", KILLED_BY_AN);
else {
mtmp->mhp -= dmg;
if (mtmp->mhp <= 0)
xkilled(mtmp, 1);
}
}
else {
if (!flooreffects(otmp, x, y, "fall")) {
place_object(otmp, x, y);
stackobj(otmp);
newsym(x, y); /* map the rock */
}
}
break;
case WAGE_OF_WRATH:
if(Breathless_res(mtmp)){
pline("%s %s unbothered.",
(mtmp == &youmonst) ? "You" : Monnam(mtmp),
(mtmp == &youmonst) ? "are" : "is");
water_damage(mtmp == &youmonst ? invent : mtmp->minvent, FALSE, FALSE, WD_BLOOD, mtmp);
}
else {
if(mtmp == &youmonst){
BloodDrown += obj->cursed ? 9 : 4;
}
else {
water_damage(mtmp->minvent, FALSE, FALSE, WD_BLOOD, mtmp);
if(obj->cursed){
//Note: 2x water damage
water_damage(mtmp->minvent, FALSE, FALSE, WD_BLOOD, mtmp);
mtmp->mbdrown = min(100, mtmp->mbdrown+9);
}
mtmp->mhp -= min(99, obj->cursed ? mtmp->mhpmax : mtmp->mhpmax/2);
if(mtmp->mhp <= 0){
pline("%s drowns in blood!", Monnam(mtmp));
mondied(mtmp);
}
else if(!resist(mtmp, RING_CLASS, 0, NOTELL)){
pline("%s is crazed with anger!", Monnam(mtmp));
mtmp->mberserk = 1;
}
}
}
break;
case WAGE_OF_ENVY:
if(mtmp != &youmonst && mindless_mon(mtmp)) { /* player is never mindless */
pline("%s is unbothered.", Monnam(mtmp));
}
if(mtmp == &youmonst){
if(!roll_madness(MAD_TALONS)){ /*May refuse to give up things*/
struct obj *otmp2;
int delay = 0;
if (*u.ushops) sellobj_state(SELL_DELIBERATE);
for(otmp = invent; otmp; otmp = otmp2) {
if(otmp == obj) {otmp2 = otmp->nobj; continue;}
if(obj->cursed && otmp->owornmask){
if(otmp->oclass == ARMOR_CLASS)
delay = max(delay, objects[otmp->otyp].oc_delay);
remove_worn_item(otmp, TRUE);
}
otmp2 = otmp->nobj;
drop(otmp);
}
if (*u.ushops) sellobj_state(SELL_NORMAL);
reset_occupations();
if(delay)
nomul(-delay, "taking off clothes");
}
}
else {
relobj_envy(mtmp,canspotmon(mtmp));
mtmp->menvy = TRUE;
if(obj->cursed){
mtmp->mdisrobe = TRUE;
}
}
break;
case WAGE_OF_PRIDE:
if(mtmp != &youmonst && mindless_mon(mtmp)){ /* player is never mindless */
pline("%s is unbothered.", Monnam(mtmp));
}
if(mtmp == &youmonst){
u.uencouraged -= 9;
if(obj->cursed)
u.ustdy += 45;
}
else {
mtmp->encouraged -= 9;
if(obj->cursed){
mtmp->mstdy += 45;
}
if(is_minion(mtmp->data) && !(mtmp->data->geno&G_UNIQ)
&& (obj->cursed || !resist(mtmp, RING_CLASS, 0, NOTELL))
){
if(In_endgame(&u.uz)){
if(canspotmon(mtmp)){
pline("%s plummets through the %s!", Monnam(mtmp), surface(mtmp->mx, mtmp->my));
}
mongone(mtmp);
}
else if(!templated(mtmp)){
if(canspotmon(mtmp)){
pline("%s falls from grace!", Monnam(mtmp));
}
set_template(mtmp, FALLEN_TEMPLATE);
}
}
}
break;
}
/* if you targeted a monster, it gets angry, even if it was unaffected */
if (mtmp) {
wakeup(mtmp, TRUE);
}
}
/* handle B/U/C effect of wages */
soul_crush_consequence(obj);
useup(obj);
return MOVE_STANDARD;
}
int
use_vital(struct obj *obj)
{
if(!freehand()){
You("can't crush %s with no free %s!", xname(obj), body_part(HAND));
return MOVE_CANCELLED;
}
if(yn("Crush the stone?") == 'y'){
if(!obj->blessed){
You_feel("full of vital energy!");
healup((obj->cursed ? 900 : 400), 0, FALSE, FALSE);
}
soul_crush_consequence(obj);
useup(obj);
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
}
int
use_spiritual(struct obj *obj)
{
if(!freehand()){
You("can't crush %s with no free %s!", xname(obj), body_part(HAND));
return MOVE_CANCELLED;
}
if(yn("Crush the stone?") == 'y'){
if(!obj->blessed) {
You_feel("deeply spiritual!");
u.uen = min(u.uenmax, u.uen + (obj->cursed ? 900 : 400));
}
soul_crush_consequence(obj);
useup(obj);
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
}
void
salve_effect(struct obj *otmp)
{
int oerodedLevel = 3;//3, 2, 1
int speLevel = -5; //-5, -1, +3
for(int i = 0; i < 3; i++){
if(otmp->oeroded >= oerodedLevel){
otmp->oeroded--;
return;
}
else if(otmp->oeroded2 >= oerodedLevel){
otmp->oeroded2--;
return;
}
else if(otmp->oeroded3 >= oerodedLevel){
otmp->oeroded3--;
return;
}
else if(is_enchantable(otmp) && otmp->spe <= speLevel){
otmp->spe = min(3, otmp->spe+2);
return;
}
oerodedLevel--;
speLevel += 4;
}
}
int
use_armor_salve(struct obj *obj)
{
struct obj *otmp;
if(!freehand()){
You("can't use salve with no free %s!", body_part(HAND));
return MOVE_CANCELLED;
}
if(obj->spe <= 0){
pline("There's no salve left.");
return MOVE_CANCELLED;
}
// Create an array with all classes explicitly listed in it, 1-MAXOCLASSES :(
char all_classes[MAXOCLASSES] = {0};
for(int i = 1; i < MAXOCLASSES; i++)
all_classes[i-1] = i;
otmp = getobj(all_classes, "salve");
if(otmp){
You("spread some salve on %s.", yname(otmp));
salve_effect(otmp);
obj->spe--;
return MOVE_STANDARD;
}
return MOVE_CANCELLED;
}
int
use_mist_projector(struct obj *obj)
{
if (obj->spe <= 0) {
pline("%s", nothing_happens);
return MOVE_CANCELLED;
}
struct region_arg cloud_data;
cloud_data.damage = 3+3*P_SKILL(P_FIREARM);
cloud_data.adtyp = AD_COLD;
(void) create_generic_cloud(u.ux, u.uy, 4+bcsign(obj), &cloud_data, TRUE);
pline("Whirling snow swirls out from around the %s.", xname(obj));
obj->spe--;
use_skill(P_FIREARM, 1);
return MOVE_STANDARD;
}
static int
res_engine_menu(struct obj *obj)
{
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
struct obj *otmp;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
// Sprintf(buf, "Do what?");
// add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
if(obj->spe < 8){
Sprintf(buf, "Replace component");
any.a_int = 1; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(obj->altmode != ENG_MODE_OFF){
Sprintf(buf, "Switch off");
any.a_int = 2; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(obj->altmode != ENG_MODE_PYS){
Sprintf(buf, "Switch to low intensity (physical only)");
any.a_int = 3; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(obj->altmode != ENG_MODE_ENR){
Sprintf(buf, "Switch to high intensity (physical and energy)");
any.a_int = 4; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
end_menu(tmpwin, "Do what?");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if( n <= 0 )
return FALSE;
switch(selected[0].item.a_int){
case 1:
otmp = getobj(tools, "replace with");
if(!otmp)
return FALSE;
else if(otmp->otyp != HELLFIRE_COMPONENT){
pline("This device requires hellfire components.");
return FALSE;
}
//else
useup(otmp);
You("put the new component into the engine.");
obj->spe = 8;
break;
case 2:
You("switch the engine off.");
obj->altmode = ENG_MODE_OFF;
break;
case 3:
You("switch the engine to low intensity.");
obj->altmode = ENG_MODE_PYS;
break;
case 4:
You("switch the engine to high intensity.");
obj->altmode = ENG_MODE_ENR;
break;
}
free(selected);
return TRUE;
}
int
check_res_engine(struct monst *mdef, int adtyp)
{
boolean youdef = (mdef == &youmonst);
struct obj *engine;
boolean vis = youdef;
for(engine = youdef ? invent : mdef->minvent; engine; engine = engine->nobj)
if(engine->otyp == PRESERVATIVE_ENGINE && engine->spe > 0 && engine->altmode != ENG_MODE_OFF){
if(adtyp == AD_VORP || adtyp == AD_SHRD || adtyp == AD_TENT || engine->altmode == ENG_MODE_ENR){
if(vis) pline("%s infernal engine whirrs.", youdef ? "Your" : s_suffix(Monnam(mdef)));
engine->spe--;
return TRUE;
}
}
return FALSE;
}
void
add_class(char *cl, char class)
{
char tmp[2];
tmp[0] = class;
tmp[1] = '\0';
Strcat(cl, tmp);
}
const int carveTurns[6] = {3,4,2,1,5,2};
int
do_carve_obj(struct obj *obj)
{
int rune;
char carveelet;
struct obj *carvee;
struct obj *otmp;
multi = 0; /* moves consumed */
nomovemsg = (char *)0; /* occupation end message */
rune = pick_rune(FALSE);
if(!rune) return MOVE_CANCELLED;
carveelet = pick_carvee();
for (otmp = invent; otmp; otmp = otmp->nobj) {
if(otmp->invlet == carveelet) break;
}
if(otmp) carvee = otmp;
else return MOVE_CANCELLED;
if(carvee == obj){
// pline("Your grasp of physics is appalling.");
pline("Is this a zen thing?");
return MOVE_CANCELLED;
}
if(carvee->spe > obj->spe){
pline("The %s is too dull to cut into the %s.", xname(obj), xname(carvee));
return MOVE_CANCELLED;
}
if(carvee->oward != 0 ){
You("chip off the existing rune.");
multi-=1;
if(carvee->oartifact) pline("The wood heals like the rune was never there.");
else if(--carvee->spe < -1*rn2(8)) {
You("destroyed the %s in the process.", xname(carvee));
useup(carvee);
return MOVE_CANCELLED;
}
}
multi -= carveTurns[rune-FIRST_RUNE];
nomovemsg = "You finish carving.";;
carvee->oward = get_wardID(rune);
You("carve a %s into the %s.",wardDecode[decode_wardID(carvee->oward)],xname(carvee));
u.uconduct.wardless++;
see_monsters(); //Some magic staves grant detection, so recheck that now.
return MOVE_STANDARD;
}
int
pick_rune(boolean describe)
{
if (!(u.wardsknown & (WARD_TOUSTEFNA | WARD_DREPRUN | WARD_OTTASTAFUR | WARD_KAUPALOKI | WARD_VEIOISTAFUR | WARD_THJOFASTAFUR))){
You("can't think of anything to carve.");
return 0;
}
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Known Magical Staves");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
if(u.wardsknown & WARD_TOUSTEFNA){
Sprintf(buf, "Toustefna stave");
any.a_int = TOUSTEFNA; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(u.wardsknown & WARD_DREPRUN){
Sprintf(buf, "Dreprun stave");
any.a_int = DREPRUN; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(u.wardsknown & WARD_VEIOISTAFUR){
Sprintf(buf, "Veioistafur stave");
any.a_int = VEIOISTAFUR; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(u.wardsknown & WARD_THJOFASTAFUR){
Sprintf(buf, "Thjofastafur stave");
any.a_int = THJOFASTAFUR; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if (!describe){
// Describe a glyph
Sprintf(buf, "Describe a glyph instead");
any.a_int = -1; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
'?', 0, ATR_NONE, buf,
MENU_UNSELECTED);
}
else {
Sprintf(buf, "Carve a glyph instead");
any.a_int = -1; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
'!', 0, ATR_NONE, buf,
MENU_UNSELECTED);
}
end_menu(tmpwin, (describe) ? "Choose stave to describe:" : "Choose stave to carve:");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if (n > 0 && selected[0].item.a_int == -1){
free(selected);
return pick_rune(!describe);
}
if (n > 0 && describe){
describe_rune(selected[0].item.a_int);
free(selected);
return pick_rune(describe);
}
if (n > 0 && !describe){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
void
describe_rune(int floorID)
{
winid datawin;
char name[80];
char turns[80];
char warded[80];
char reinforce[80];
char secondary[80];
switch (floorID){
case TOUSTEFNA:
strcpy(name, " Toustefna stave");
strcpy(turns, " 3 turns");
strcpy(warded, " d, f");
strcpy(secondary, " None.");
break;
case DREPRUN:
strcpy(name, " Dreprun stave");
strcpy(turns, " 4 turns");
strcpy(warded, " q, u, bats, birds");
strcpy(secondary, " None.");
break;
case VEIOISTAFUR:
strcpy(name, " Veioistafur stave");
strcpy(turns, " 5 turns");
strcpy(warded, " ;");
strcpy(secondary, " Bonus d20 damage vs ; when carved onto wielded weapon.");
break;
case THJOFASTAFUR:
strcpy(name, " Thjofastafur stave");
strcpy(turns, " 2 turns");
strcpy(warded, " n, l");
strcpy(secondary, " Grants detection of nymphs and leprechauns while wielded.");
break;
default:
impossible("No such stave to carve: %d", floorID);
return;
}
datawin = create_nhwindow(NHW_TEXT);
putstr(datawin, 0, "");
putstr(datawin, 0, name);
putstr(datawin, 0, "");
putstr(datawin, 0, " Turns to carve:");
putstr(datawin, 0, turns);
putstr(datawin, 0, "");
putstr(datawin, 0, " Warded creatures:");
putstr(datawin, 0, warded);
putstr(datawin, 0, "");
putstr(datawin, 0, " Secondary effects:");
putstr(datawin, 0, secondary);
putstr(datawin, 0, "");
display_nhwindow(datawin, FALSE);
destroy_nhwindow(datawin);
return;
}
char
pick_carvee(void)
{
winid tmpwin;
int n=0, how,count=0;
char buf[BUFSZ];
struct obj *otmp;
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Carvable items");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
for(otmp = invent; otmp; otmp = otmp->nobj){
if(otmp->oclass == WEAPON_CLASS && otmp->obj_material == WOOD && otmp->otyp != MOON_AXE
&& otmp->oartifact != ART_BOW_OF_SKADI && otmp->oartifact != ART_GUNGNIR
&& otmp->oartifact != ART_STAFF_OF_AESCULAPIUS && otmp->oartifact != ART_ESSCOOAHLIPBOOURRR){
Sprintf1(buf, doname(otmp));
any.a_char = otmp->invlet; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
otmp->invlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
count++;
}
}
end_menu(tmpwin, "Choose ward:");
how = PICK_ONE;
if(count) n = select_menu(tmpwin, how, &selected);
else You("don't have any carvable items.");
destroy_nhwindow(tmpwin);
if(n > 0){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
static boolean
clockwork_location_checks(struct obj *obj, coord *cc, int quietly)
{
xchar x,y;
x = cc->x; y = cc->y;
if (!isok(x,y)) {
if (!quietly)
You("cannot build a clockwork there.");
return FALSE;
}
if (IS_ROCK(levl[x][y].typ) &&
!(species_passes_walls(&mons[obj->corpsenm]) && may_passwall(x,y))) {
if (!quietly)
You("cannot build a clockwork in %s!",
IS_TREES(levl[x][y].typ) ? "a tree" : "solid rock");
return FALSE;
}
if (boulder_at(x,y) && !species_passes_walls(&mons[obj->corpsenm])
&& !throws_rocks(&mons[obj->corpsenm])) {
if (!quietly)
You("cannot fit a clockwork under the %s.",xname(boulder_at(x,y)));
return FALSE;
}
if (m_at(x,y)) {
if (!quietly)
You("cannot fit a clockwork there!");
return FALSE;
}
return TRUE;
}
static struct permonst *
clockworkMenu(struct obj *obj)
{
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Clockwork types");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
if(obj->otyp == CLOCKWORK_COMPONENT){
Sprintf(buf, "clockwork soldier");
any.a_int = PM_CLOCKWORK_SOLDIER; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
Sprintf(buf, "clockwork dwarf");
any.a_int = PM_CLOCKWORK_DWARF; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
Sprintf(buf, "faberge sphere");
any.a_int = PM_FABERGE_SPHERE; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
} else if(obj->otyp == SUBETHAIC_COMPONENT){
Sprintf(buf, "golden heart");
any.a_int = PM_GOLDEN_HEART; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
} else if(obj->otyp == HELLFIRE_COMPONENT){
Sprintf(buf, "hellfire orb");
any.a_int = PM_HELLFIRE_ORB; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
end_menu(tmpwin, "Choose type:");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n > 0){
struct permonst * picked = &mons[selected[0].item.a_int];
free(selected);
return picked;
}
return (struct permonst *) 0;
}
static int
doUseComponents(struct obj **optr)
{
struct obj *obj = *optr;
struct monst *mm = (struct monst *)0;
struct permonst *pmm;
coord cc;
if(!getdir((char *)0)) {
return MOVE_CANCELLED;
}
if (u.uswallow && (u.dx || u.dy || u.dz)) {
/* can't activate a figurine while swallowed */
You("don't have enough room in here to build a clockwork.");
return MOVE_CANCELLED;
}
if (!(u.dx || u.dy || u.dz))
mm = &youmonst;
else if (u.dz > 0 && u.usteed)
mm = u.usteed;
else if (isok(u.ux + u.dx, u.uy + u.dy))
mm = m_at(u.ux + u.dx, u.uy + u.dy);
if (mm) {
/* check that the part matches the creature's needed type */
boolean can_use_obj = FALSE;
if (is_clockwork(mm->data)) {
switch (mm->mtyp) {
case PM_GOLDEN_HEART:
case PM_ID_JUGGERNAUT:
can_use_obj = (obj->otyp == SUBETHAIC_COMPONENT);
break;
case PM_HELLFIRE_ORB:
case PM_HELLFIRE_COLOSSUS:
can_use_obj = (obj->otyp == HELLFIRE_COMPONENT);
break;
case PM_SCRAP_TITAN:
can_use_obj = (obj->otyp == CLOCKWORK_COMPONENT
|| obj->otyp == SUBETHAIC_COMPONENT
|| obj->otyp == HELLFIRE_COMPONENT
|| obj->otyp == SCRAP);
break;
default:
/* androids need the rarer subethaic components */
if (is_android(mm->data))
can_use_obj = (obj->otyp == SUBETHAIC_COMPONENT);
/* all other clockworks need standard clockwork components */
else
can_use_obj = (obj->otyp == CLOCKWORK_COMPONENT);
break;
}
}
else {
if (mm == &youmonst)
You("aren't made of clockwork!");
else
pline("It isn't made of clockwork.");
return MOVE_CANCELLED;
}
/* check we have the right type of part */
if (!can_use_obj) {
if (mm == &youmonst)
You("can't repair yourself with this kind of part.");
else
pline("It can't take this kind of part.");
return MOVE_CANCELLED;
}
if (mm != &youmonst) {
/* repairing monsters */
if (mm->mhp < mm->mhpmax){
if (yn("Repair it?") == 'y'){
mm->mhp += mm->m_lev;
if (mm->mhp > mm->mhpmax)
mm->mhp = mm->mhpmax;
useup(obj);
*optr = 0;
return MOVE_STANDARD;
}
}
else {
pline("It doesn't need repairs.");
return MOVE_CANCELLED;
}
/* done */
}
else {
/* repairing yourself */
if (uhp() >= uhpmax()) {
You("don't need repairs.");
return MOVE_CANCELLED;
}
else {
healup(Upolyd ? mons[u.umonnum].mlevel : u.ulevel, 0, FALSE, FALSE);
/* subethaic components also restore a small amount of pw */
if (obj->otyp == SUBETHAIC_COMPONENT) {
u.uen += d(4,2);
if (u.uen > u.uenmax)
u.uen = u.uenmax;
}
useup(obj);
*optr = 0;
return MOVE_STANDARD;
}
/* done */
}
}
else {
/* no one there, attempt to make a clockwork servant */
/* Scrap is useless in making clockworks */
if (obj->otyp == SCRAP) {
You("can't build anything with this worthless scrap.");
return MOVE_CANCELLED;
}
cc.x = u.ux + u.dx; cc.y = u.uy + u.dy;
/* Passing FALSE arg here will result in messages displayed */
if (obj->quan < 10 && obj->otyp != SCRAP){
You("don't have enough components to build a clockwork servant.");
return MOVE_CANCELLED;
}
pmm = clockworkMenu(obj);
if (!pmm) return MOVE_CANCELLED;
if (!clockwork_location_checks(obj, &cc, FALSE)) return MOVE_CANCELLED;
You("build a clockwork and %s.",
(u.dx || u.dy) ? "set it beside you" :
(Weightless || Is_waterlevel(&u.uz) ||
is_pool(cc.x, cc.y, TRUE)) ?
"release it" :
(u.dz < 0 ?
"toss it into the air" :
"set it on the ground"));
mm = makemon(pmm, u.ux + u.dx, u.uy + u.dy, MM_EDOG | MM_ADJACENTOK | NO_MINVENT | MM_NOCOUNTBIRTH);
if (mm){
initedog(mm);
mm->m_lev = u.ulevel / 2 + 1;
mm->mhpmax = (mm->m_lev * hd_size(mm->data)) - hd_size(mm->data)/2;
mm->mhp = mm->mhpmax;
mm->mtame = 10;
mm->mpeaceful = 1;
if ((u.dx || u.dy) && is_vectored_mtyp(mm->mtyp)){
mm->mvar_vector = -1;
while (xdir[(int)(++mm->mvar_vector)] != u.dx || ydir[(int)mm->mvar_vector] != u.dy);
}
}
obj->quan -= 9;
useup(obj);
*optr = 0;
return MOVE_STANDARD;
}
/* if we used up the part, this took time */
return ((*optr) == 0) ? MOVE_STANDARD : MOVE_CANCELLED;
}
static long
upgradeMenu(void)
{
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Upgrade types");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
if(!(u.clockworkUpgrades&OIL_STOVE)){
Sprintf(buf, "oil stove");
any.a_int = 1; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&WOOD_STOVE) && u.clockworkUpgrades&OIL_STOVE){
Sprintf(buf, "wood stove");
any.a_int = 2; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&FAST_SWITCH)){
Sprintf(buf, "fast speed switch");
any.a_int = 3; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&EFFICIENT_SWITCH)){
Sprintf(buf, "efficient speed switch");
any.a_int = 4; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&ARMOR_PLATING)){
Sprintf(buf, "armor plating");
any.a_int = 5; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&PHASE_ENGINE)){
Sprintf(buf, "phase engine");
any.a_int = 6; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&MAGIC_FURNACE) && u.clockworkUpgrades&OIL_STOVE){
Sprintf(buf, "magic furnace");
any.a_int = 7; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&HELLFIRE_FURNACE) && u.clockworkUpgrades&OIL_STOVE){
Sprintf(buf, "hellfire furnace");
any.a_int = 8; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&SCRAP_MAW)){
Sprintf(buf, "scrap maw");
any.a_int = 9; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
if(!(u.clockworkUpgrades&HIGH_TENSION)){
Sprintf(buf, "high-tension spring");
any.a_int = 10; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
end_menu(tmpwin, "Choose type:");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n > 0){
long picked = 0x1L<<(selected[0].item.a_int - 1);
free(selected);
return picked;
}
return 0;
}
boolean
set_obj_shape(struct obj *obj, long shape)
{
long starting_shape = obj->bodytypeflag;
//Dragon scales don't have a shape.
if(Is_dragon_scales(obj))
return FALSE;
if(is_shirt(obj) || is_suit(obj)){
//Only CHANGE the shape if the result will be valid.
if(shape&MB_BODYTYPEMASK){
//Body gloves cover the whole body.
if(obj->otyp == BODYGLOVE)
obj->bodytypeflag = shape&MB_BODYTYPEMASK;
//Shirts, dresses, and togas aren't concerned by the shape of the lower body.
else if (is_shirt(obj) || obj->otyp == ELVEN_TOGA || is_dress(obj->otyp))
obj->bodytypeflag = (shape&MB_HUMANOID) ? MB_HUMANOID : (shape&MB_BODYTYPEMASK);
else if (is_suit(obj))
obj->bodytypeflag = shape&MB_BODYTYPEMASK;
}
//If the given shape is invalid and the object's current shape is invalid, set the object to humanoid.
// I believe this will never happen, as armor is initialized to humanoid.
else if((obj->bodytypeflag&MB_BODYTYPEMASK) == 0)
obj->bodytypeflag = MB_HUMANOID;
}
else if (is_helmet(obj) && !is_hat(obj))
obj->bodytypeflag = shape&MB_HEADMODIMASK;
if(obj->bodytypeflag != starting_shape)
return TRUE;
return FALSE;
}
static int
resizeArmor(struct obj *kit)
{
struct obj *otmp;
struct permonst *ptr;
struct monst *mtmp;
int rx, ry;
boolean changed = FALSE;
if (!getdir("Resize armor or tool to fit what creature? (in what direction)")) {
/* decided not to */
return MOVE_CANCELLED;
}
if (u.usteed && u.dz > 0) ptr = u.usteed->data;
else
if(u.dz){
pline("No creature there.");
return MOVE_CANCELLED;
} else if (u.dx == 0 && u.dy == 0) {
ptr = youracedata;
} else {
rx = u.ux+u.dx; ry = u.uy+u.dy;
mtmp = m_at(rx, ry);
if(!mtmp){
pline("No creature there.");
return MOVE_CANCELLED;
}
ptr = mtmp->data;
}
// attempt to find a piece of armor to resize
const char clothes[] = { ARMOR_CLASS, TOOL_CLASS, 0 };
otmp = getobj(clothes, "resize");
if (!otmp) return MOVE_CANCELLED;
if(otmp == kit){
You("cannot resize an upgrade kit with itself!");
return MOVE_CANCELLED;
}
// check that the armor is not currently being worn
if (otmp->owornmask){
You("are wearing that!");
return MOVE_CANCELLED;
}
// check that the armor is not dragon scales (which cannot be resized)
if (Is_dragon_scales(otmp)){
pline("Dragon scales cannot be resized.");
return MOVE_CANCELLED;
}
// change shape
if (is_shirt(otmp) || otmp->otyp == ELVEN_TOGA || is_suit(otmp)){
//Check that the monster can actually have armor that fits it.
if(!(ptr->mflagsb&MB_BODYTYPEMASK)){
You("can't figure out how to make it fit.");
return MOVE_CANCELLED;
}
changed |= set_obj_shape(otmp, ptr->mflagsb);
}
else if (is_helmet(otmp) && !is_hat(otmp)){
//Check that the monster can actually have armor that fits it.
if(!has_head(ptr)){
pline("No head!");
return MOVE_CANCELLED;
}
changed |= set_obj_shape(otmp, ptr->mflagsb);
}
// change size (AFTER shape, because this may be aborted during that step.
if(otmp->objsize != ptr->msize){
otmp->objsize = ptr->msize;
changed = TRUE;
}
fix_object(otmp);
if(otmp->obroken && otmp->otyp == POWER_ARMOR){
pline("Your power armor starts working!");
otmp->obroken = 0;
changed = TRUE;
}
if(!changed){
You("figure it already fits fine.");
return MOVE_CANCELLED;
}
You("resize the %s to fit.", otmp->oclass == TOOL_CLASS?"tool":"armor");
pline("The kit is used up.");
return MOVE_STANDARD;
}
#define STANDARD_UPGRADE(prop, subsystem) \
if(check_imp_mod(arm, prop)){ \
pline("You've already repaired the %s.", subsystem); \
return MOVE_CANCELLED; \
} \
else { \
pline("You repair the %s.", subsystem); \
add_imp_mod(arm, prop); \
add_imp_record(prop);\
useup(upitm); \
return MOVE_STANDARD; \
}
static int
upgradeImpArmor(void)
{
struct obj *upitm;
struct obj *arm = getobj(apply_armor, "armor piece to repair");
if(!arm){
return MOVE_CANCELLED;
}
if(!is_imperial_elven_armor(arm)){
pline("That doesn't look like a piece of imperial armor.");
return MOVE_CANCELLED;
}
if(check_imp_mod(arm, IEA_NOUPGRADES)){
pline("This less-sophisticated armor may lack certain functions, but that is not the result of damage.");
return MOVE_CANCELLED;
}
if(arm->owornmask){
You("will need to take that off to repair it.");
return MOVE_CANCELLED;
}
switch(arm->otyp){
case IMPERIAL_ELVEN_HELM:
upitm = getobj(imperial_repairs, "repair the helm with");
if(!upitm || !helm_upgrade_obj(upitm)){
pline("Never mind.");
return MOVE_CANCELLED;
}
if(upitm->owornmask){
pline("You're still using that.");
return MOVE_CANCELLED;
}
if(upitm->oartifact){
pline("It resists the attempt!");
return MOVE_CANCELLED;
}
switch(upitm->otyp){
case AMULET_OF_MAGICAL_BREATHING:
STANDARD_UPGRADE(IEA_NOBREATH, "life-support subsystem")
break;
case WAN_DRAINING:
STANDARD_UPGRADE(IEA_LIFESENSE, "life-sign sensor")
break;
case RIN_SEE_INVISIBLE:
STANDARD_UPGRADE(IEA_SEE_INVIS, "crystal eye")
break;
case HELM_OF_TELEPATHY:
case AMULET_OF_ESP:
STANDARD_UPGRADE(IEA_TELEPAT, "extrasensory perception subsystem")
break;
case CRYSTAL_HELM:
STANDARD_UPGRADE(IEA_BLIND_RES, "visor")
break;
case RIN_INCREASE_ACCURACY:
STANDARD_UPGRADE(IEA_INC_ACC, "targetting subsystem")
break;
case RIN_TELEPORT_CONTROL:
STANDARD_UPGRADE(IEA_TELE_CNTRL, "teleportation control subsystem")
break;
case RIN_PROTECTION_FROM_SHAPE_CHAN:
STANDARD_UPGRADE(IEA_PROT_SHAPE, "self-bored lens")
break;
default:
impossible("Unknown repair component, sorry :(.");
return MOVE_CANCELLED;
break;
}
break;
case IMPERIAL_ELVEN_GAUNTLETS:
upitm = getobj(imperial_repairs, "repair the gauntlets with");
if(!upitm || !gauntlets_upgrade_obj(upitm)){
pline("Never mind.");
return MOVE_CANCELLED;
}
if(upitm->owornmask){
pline("You're still using that.");
return MOVE_CANCELLED;
}
if(upitm->oartifact){
pline("It resists the attempt!");
return MOVE_CANCELLED;
}
switch(upitm->otyp){
case WATER_WALKING_BOOTS:
STANDARD_UPGRADE(IEA_SWIMMING, "swimming webs")
break;
case GAUNTLETS_OF_POWER:
STANDARD_UPGRADE(IEA_GOPOWER, "power servos")
break;
case GAUNTLETS_OF_DEXTERITY:
STANDARD_UPGRADE(IEA_GODEXTERITY, "dexterity servos")
break;
case RIN_INCREASE_DAMAGE:
STANDARD_UPGRADE(IEA_INC_DAM, "microtargetting servos")
break;
case WAN_MAGIC_MISSILE:
STANDARD_UPGRADE(IEA_BOLTS, "missile projectors")
break;
case AMULET_OF_STRANGULATION:
STANDARD_UPGRADE(IEA_STRANGLE, "grappling servos")
break;
default:
impossible("Unknown repair component, sorry :(.");
return MOVE_CANCELLED;
break;
}
break;
case IMPERIAL_ELVEN_ARMOR:
upitm = getobj(imperial_repairs, "repair the armor with");
if(!upitm || !armor_upgrade_obj(upitm)){
pline("Never mind.");
return MOVE_CANCELLED;
}
if(upitm->owornmask){
pline("You're still using that.");
return MOVE_CANCELLED;
}
if(upitm->oartifact){
pline("It resists the attempt!");
return MOVE_CANCELLED;
}
switch(upitm->otyp){
case FLYING_BOOTS:
STANDARD_UPGRADE(IEA_FLYING, "moth wings")
break;
case RIN_SUSTAIN_ABILITY:
STANDARD_UPGRADE(IEA_FIXED_ABIL, "stasis subsystem")
break;
case RIN_REGENERATION:
case AMULET_OF_WOUND_CLOSURE:
STANDARD_UPGRADE(IEA_FAST_HEAL, "medical subsystem")
break;
case AMULET_OF_REFLECTION:
case SHIELD_OF_REFLECTION:
case JUMPSUIT:
STANDARD_UPGRADE(IEA_REFLECTING, "reflective chestplate")
break;
case AMULET_VERSUS_SICKNESS:
case HEALER_UNIFORM:
STANDARD_UPGRADE(IEA_SICK_RES, "sealed bodyglove")
break;
case CLOAK_OF_PROTECTION:
STANDARD_UPGRADE(IEA_HALF_PHDAM, "ballistic base layer")
break;
case CLOAK_OF_MAGIC_RESISTANCE:
case ORIHALCYON_GAUNTLETS:
STANDARD_UPGRADE(IEA_HALF_SPDAM, "dispersive underlayer")
break;
case CLOAK_OF_DISPLACEMENT:
STANDARD_UPGRADE(IEA_DISPLACED, "holographic projector")
break;
case CLOAK_OF_INVISIBILITY:
case RIN_INVISIBILITY:
case WAN_MAKE_INVISIBLE:
STANDARD_UPGRADE(IEA_INVIS, "active camouflage system")
break;
case RIN_PROTECTION:
STANDARD_UPGRADE(IEA_DEFLECTION, "deflectors")
break;
case ELVEN_MITHRIL_COAT:
STANDARD_UPGRADE(IEA_MITHRIL, "mithril articulations")
break;
default:
impossible("Unknown repair component, sorry :(.");
return MOVE_CANCELLED;
break;
}
break;
case IMPERIAL_ELVEN_BOOTS:
upitm = getobj(imperial_repairs, "repair the boots with");
if(!upitm || !boots_upgrade_obj(upitm)){
pline("Never mind.");
return MOVE_CANCELLED;
}
if(upitm->owornmask){
pline("You're still using that.");
return MOVE_CANCELLED;
}
if(upitm->oartifact){
pline("It resists the attempt!");
return MOVE_CANCELLED;
}
switch(upitm->otyp){
case JUMPING_BOOTS:
STANDARD_UPGRADE(IEA_JUMPING, "jump jets")
break;
case WAN_SPEED_MONSTER:
case RIN_ALACRITY:
case SPEED_BOOTS:
STANDARD_UPGRADE(IEA_FAST, "speed boosters")
break;
case WAN_TELEPORTATION:
case RIN_TELEPORTATION:
STANDARD_UPGRADE(IEA_TELEPORT, "blink subsystem")
break;
case KICKING_BOOTS:
STANDARD_UPGRADE(IEA_KICKING, "concussive impactors")
break;
default:
impossible("Unknown repair component, sorry :(.");
return MOVE_CANCELLED;
break;
}
break;
default:
impossible("Unknown armor piece?");
return MOVE_CANCELLED;
break;
}
}
static int
doUseUpgradeKit(struct obj **optr)
{
struct obj *obj = *optr;
struct obj *comp;
// Create an array with all classes explicitly listed in it, 1-MAXOCLASSES :(
char all_classes[MAXOCLASSES] = {0};
for(int i = 1; i < MAXOCLASSES; i++)
all_classes[i-1] = i;
if(uclockwork){
if (yn("Make an upgrade to yourself?") == 'y'){
long upgrade = upgradeMenu();
switch(upgrade){
case OIL_STOVE:
You("use the components in the upgrade kit to install an oil stove.");
u.clockworkUpgrades |= upgrade;
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case WOOD_STOVE:
comp = getobj(tools, "upgrade your stove with");
if(!comp || comp->otyp != TINNING_KIT){
pline("Never mind.");
return MOVE_CANCELLED;
}
You("use the components in the upgrade kit and the tinning kit to install a wood-burning stove.");
u.clockworkUpgrades |= upgrade;
useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case FAST_SWITCH:
You("use the components in the upgrade kit to install a fast switch on your clock.");
u.clockworkUpgrades |= upgrade;
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case EFFICIENT_SWITCH:
comp = getobj(tools, "upgrade your switch with");
if(!comp || comp->otyp != CROSSBOW){
pline("Never mind.");
return MOVE_CANCELLED;
}
You("use the components in the upgrade kit and the crossbow to upgrade the switch on your clock.");
u.clockworkUpgrades |= upgrade;
useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case ARMOR_PLATING:
comp = getobj(apply_armor, "upgrade your armor with");
if(!comp ||
!((comp->otyp == ARCHAIC_PLATE_MAIL || comp->otyp == PLATE_MAIL) &&
(comp->obj_material == COPPER))){
pline("Never mind.");
return MOVE_CANCELLED;
}
You("use the components in the upgrade kit to reinforce your armor with bronze plates.");
u.clockworkUpgrades |= upgrade;
useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case PHASE_ENGINE:
comp = getobj(all_classes, "build a phase engine with");
if(!comp || comp->otyp != SUBETHAIC_COMPONENT){
pline("Never mind.");
return MOVE_CANCELLED;
}
You("combine the components in the upgrade kit with the subethaic component and build a phase engine.");
u.clockworkUpgrades |= upgrade;
useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case MAGIC_FURNACE:
comp = getobj(apply_wand, "build a magic furnace with");
if(!comp || comp->otyp != WAN_DRAINING){
pline("Never mind.");
return MOVE_CANCELLED;
}
You("combine the components in the upgrade kit with the wand and build a magic furnace.");
u.clockworkUpgrades |= upgrade;
useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case HELLFIRE_FURNACE:
comp = getobj(all_classes, "build a hellfire furnace with");
if(!comp || comp->otyp != HELLFIRE_COMPONENT){
pline("Never mind.");
return MOVE_CANCELLED;
}
You("combine the components in the upgrade kit with the hellfire component and build a hellfire furnace.");
u.clockworkUpgrades |= upgrade;
useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case SCRAP_MAW:
comp = getobj(tools, "build a scrap maw with");
if(!comp || comp->otyp != SCRAP){
pline("Never mind.");
return MOVE_CANCELLED;
}
You("combine the components in the upgrade kit with the scrap and build a scrap maw.");
u.clockworkUpgrades |= upgrade;
useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
case HIGH_TENSION:
// Maybe one day a spring pistol or something
// comp = getobj(tools, "build a scrap maw with");
// if(!comp || comp->otyp != SCRAP){
// pline("Never mind.");
// return MOVE_CANCELLED;
// }
You("use the components in the upgrade kit to increase the maximum tension in your mainspring.");
u.uhungermax += DEFAULT_HMAX; // 2000 per, capped at 9 kits for 20,000 max
if(u.uhungermax >= DEFAULT_HMAX*10) u.clockworkUpgrades |= upgrade;
// useup(comp);
useup(obj);
*optr = 0;
return MOVE_STANDARD;
break;
}
}
}
if(u.uiearepairs && carrying_imperial_elven_armor()){
if (yn("Repair your imperial armor?") == 'y'){
if (upgradeImpArmor() != MOVE_CANCELLED){
useup(obj);
*optr = 0;
return MOVE_STANDARD;
}
}
}
if (yn("Resize a piece of armor or tool?") == 'y'){
if (resizeArmor(obj) != MOVE_CANCELLED){
useup(obj);
*optr = 0;
return MOVE_STANDARD;
}
else
return MOVE_CANCELLED;
}
return MOVE_CANCELLED;
}
int
doapply(void)
{
struct obj *obj;
int res = MOVE_DEFAULT;
int waslabile = FALSE;
char class_list[MAXOCLASSES+2];
if(check_capacity((char *)0)) return MOVE_CANCELLED;
if (carrying(POT_OIL) || uhave_graystone() || carrying(ROCK))
Strcpy(class_list, tools_too);
else
Strcpy(class_list, tools);
add_class(class_list, COIN_CLASS);
if (carrying(CREAM_PIE) || carrying(EUCALYPTUS_LEAF))
add_class(class_list, FOOD_CLASS);
if (carrying(DWARVISH_HELM) || carrying(LANTERN_PLATE_MAIL) ||
carrying(GNOMISH_POINTY_HAT) || carrying(DROVEN_CLOAK) || carrying_art(ART_GREAT_CLAWS_OF_URDLEN) ||
carrying_art(ART_AEGIS) || carrying(EILISTRAN_ARMOR) || carrying_art(ART_RED_CORDS_OF_ILMATER) || carrying(POWER_ARMOR))
add_class(class_list, ARMOR_CLASS);
if(carrying_applyable_ring()){
add_class(class_list, RING_CLASS);
}
if(carrying_applyable_amulet()){
add_class(class_list, AMULET_CLASS);
}
if(carrying_applyable_gem()){
add_class(class_list, GEM_CLASS);
}
obj = getobj(class_list, "use or apply");
if(!obj) return MOVE_CANCELLED;
waslabile = objects[obj->otyp].oc_merge; //Some functions leave a stale pointer here if they merge the item
waslabile |= obj->otyp == DOLL_S_TEAR; //Not mergeable, but still consumable.
if (obj->oartifact && !(uwep == obj && is_pole(obj)) && !touch_artifact(obj, &youmonst, FALSE))
return MOVE_STANDARD; /* evading your grasp costs a turn; just be
grateful that you don't drop it as well */
if(obj->ostolen && u.sealsActive&SEAL_ANDROMALIUS) unbind(SEAL_ANDROMALIUS, TRUE);
if (obj->oclass == WAND_CLASS)
return do_break_wand(obj);
else if (obj->oclass == COIN_CLASS)
return do_flip_coin(obj);
else if (obj->oclass == SCOIN_CLASS)
return do_soul_coin(obj);
else if (obj->oclass == RING_CLASS || obj->oclass == AMULET_CLASS)
return do_present_item(obj);
else if(is_knife(obj) && !(obj->oartifact==ART_PEN_OF_THE_VOID && obj->ovar1_seals&SEAL_MARIONETTE))
return do_carve_obj(obj);
if(obj->oartifact == ART_SILVER_STARLIGHT) res = do_play_instrument(obj);
else if(obj->oartifact == ART_HOLY_MOONLIGHT_SWORD && !u.veil) use_lamp(obj);
else if(obj->oartifact == ART_BLOODLETTER && artinstance[obj->oartifact].BLactive >= monstermoves) res = do_bloodletter(obj);
else if(obj->oartifact == ART_AEGIS) res = swap_aegis(obj);
else if(is_tipped_spear(obj)) res = swap_point(obj);
else if(obj->oartifact == ART_STAFF_OF_AESCULAPIUS) res = aesculapius_poke(obj);
else if(obj->oartifact == ART_ESSCOOAHLIPBOOURRR) res = aesculapius_poke(obj);
else if(obj->oartifact == ART_RED_CORDS_OF_ILMATER) res = ilmater_touch(obj);
else if(obj->otyp == RAKUYO || obj->otyp == RAKUYO_SABER){
return use_rakuyo(obj);
}
else if(obj->otyp == BLADE_OF_MERCY || obj->otyp == BLADE_OF_GRACE){
return use_mercy_blade(obj);
} else if(obj->otyp == DOUBLE_FORCE_BLADE || obj->otyp == FORCE_BLADE){
return use_force_blade(obj);
} else switch(obj->otyp){
case BLINDFOLD:
case NIGHT_VISION_GOGGLES:
case ANDROID_VISOR:
case LENSES:
case SUNGLASSES:
case SOUL_LENS:
case LIVING_MASK:
case R_LYEHIAN_FACEPLATE:
case MASK:
if (obj == ublindf) {
if (!cursed(obj)) Blindf_off(obj);
} else if (ublindf){
You("are already %s.",
ublindf->otyp == TOWEL ? "covered by a towel" :
(ublindf->otyp == MASK || ublindf->otyp == LIVING_MASK || ublindf->otyp == R_LYEHIAN_FACEPLATE ) ? "wearing a mask" :
(ublindf->otyp == BLINDFOLD || ublindf->otyp == ANDROID_VISOR) ? "wearing a blindfold" :
"wearing lenses");
} else if((obj->otyp == LENSES || obj->otyp == SUNGLASSES)
&& obj->objsize != youracedata->msize
){
pline("They don't fit!");
} else
Blindf_on(obj);
break;
case CREAM_PIE:
res = use_cream_pie(obj);
break;
case FORCE_SWORD:
res = use_force_sword(obj);
break;
case FORCE_WHIP:
case VIPERWHIP:
case BULLWHIP:
res = use_whip(obj);
break;
case NUNCHAKU:
res = use_nunchucks(obj);
break;
case GRAPPLING_HOOK:
res = use_grapple(obj);
break;
case SHEPHERD_S_CROOK:
res = use_crook(obj);
break;
case BOX:
case CHEST:
case ICE_BOX:
case SACK:
case SARCOPHAGUS:
case BAG_OF_HOLDING:
case OILSKIN_SACK:
res = use_container(obj, 1);
goto xit2; /* obj may have been destroyed */
break;
case BAG_OF_TRICKS:
bagotricks(obj, FALSE, (int *) 0);
break;
case CAN_OF_GREASE:
use_grease(obj);
break;
case POTION_VAPORIZER:
vape(obj);
break;
case LOCK_PICK:
case CREDIT_CARD:
case SKELETON_KEY:
res = pick_lock(&obj);
break;
case UNIVERSAL_KEY:
res = pick_lock(&obj);
break;
case PICK_AXE:
case DWARVISH_MATTOCK:
case SEISMIC_HAMMER:
res = use_pick_axe(obj);
break;
case TINNING_KIT:
use_tinning_kit(obj);
break;
case TREPHINATION_KIT:
use_trephination_kit(obj);
break;
case LEASH:
use_leash(obj);
break;
case SADDLE:
res = use_saddle(obj);
break;
case MAGIC_WHISTLE:
use_magic_whistle(obj);
break;
case WHISTLE:
use_whistle(obj);
res = MOVE_PARTIAL;
break;
case EUCALYPTUS_LEAF:
/* MRKR: Every Australian knows that a gum leaf makes an */
/* excellent whistle, especially if your pet is a */
/* tame kangaroo named Skippy. */
if (obj->blessed) {
use_magic_whistle(obj);
/* sometimes the blessing will be worn off */
if (!rn2(49)) {
if(obj->quan > 1) obj = splitobj(obj, 1L);
if (!Blind) {
char buf[BUFSZ];
pline("%s %s %s.", Shk_Your(buf, obj),
aobjnam(obj, "glow"), hcolor("brown"));
obj->bknown = 1;
}
unbless(obj);
obj_extract_self(obj); /* free from inv */
/* shouldn't merge */
obj = hold_another_object(obj, "You drop %s!",
doname(obj), (const char *)0);
}
} else {
use_whistle(obj);
}
break;
case STETHOSCOPE:
res = use_stethoscope(obj);
break;
case MIRROR:
res = use_mirror(&obj);
break;
case SPOON:
if(Role_if(PM_CONVICT)) pline("The guards used to hand these out with our food rations. No one was ever able to figure out why.");
else pline("You have never in your life seen such an odd item. You have no idea how to use it.");
break;
case BELL:
case BELL_OF_OPENING:
use_bell(&obj, FALSE);
break;
case CANDELABRUM_OF_INVOCATION:
use_candelabrum(obj);
break;
case WAX_CANDLE:
case TALLOW_CANDLE:
case CANDLE_OF_INVOCATION:
case GNOMISH_POINTY_HAT:
use_candle(&obj);
break;
case BULLET_FABBER:
if(!(Role_if(PM_ANACHRONONAUT) || Role_if(PM_TOURIST))) pline("It seems inert.");
else {
static const char all_count[] = { ALLOW_COUNT, WEAPON_CLASS, GEM_CLASS, 0 };
struct obj *otmp = getobj(all_count, "feed to the fabber");
if (!otmp || otmp->oartifact) break;
switch(otmp->otyp){
case ROCK:
obj_extract_and_unequip_self(otmp);
otmp = poly_obj(otmp,BULLET);
otmp = hold_another_object(otmp, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(otmp, "slip")),
(const char *)0);
break;
case SILVER_SLINGSTONE:
obj_extract_and_unequip_self(otmp);
otmp = poly_obj(otmp,SILVER_BULLET);
otmp->quan *= 2;
otmp->owt = weight(otmp);
otmp = hold_another_object(otmp, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(otmp, "slip")),
(const char *)0);
break;
case FLINT:
obj_extract_and_unequip_self(otmp);
otmp = poly_obj(otmp,SHOTGUN_SHELL);
otmp = hold_another_object(otmp, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(otmp, "slip")),
(const char *)0);
break;
case LOADSTONE:
obj_extract_and_unequip_self(otmp);
otmp = poly_obj(otmp,ROCKET);
otmp = hold_another_object(otmp, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(otmp, "slip")),
(const char *)0);
break;
case BULLET:
obj_extract_and_unequip_self(otmp);
otmp = poly_obj(otmp,SHOTGUN_SHELL);
otmp = hold_another_object(otmp, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(otmp, "slip")),
(const char *)0);
break;
case SHOTGUN_SHELL:
obj_extract_and_unequip_self(otmp);
otmp = poly_obj(otmp,BULLET);
otmp = hold_another_object(otmp, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(otmp, "slip")),
(const char *)0);
break;
case SILVER_BULLET:
if(otmp->quan >= 10){
struct obj *rocket;
rocket = mksobj(ROCKET, MKOBJ_NOINIT);
rocket->blessed = otmp->blessed;
rocket->cursed = otmp->cursed;
rocket->quan = (otmp->quan)/10;
rocket->spe = otmp->spe;
rocket->dknown = TRUE;
rocket->known = otmp->known;
rocket->bknown = otmp->bknown;
rocket->rknown = otmp->rknown;
rocket->sknown = otmp->sknown;
if((otmp->quan = (otmp->quan)%10) == 0) useup(otmp);
else otmp->owt = weight(otmp);
rocket->owt = weight(rocket);
rocket = hold_another_object(rocket, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(rocket, "slip")),
(const char *)0);
}break;
case ROCKET:{
struct obj *bullets;
bullets = mksobj(SILVER_BULLET, MKOBJ_NOINIT);
bullets->blessed = otmp->blessed;
bullets->cursed = otmp->cursed;
bullets->quan = (otmp->quan)*10;
bullets->spe = otmp->spe;
bullets->dknown = TRUE;
bullets->known = otmp->known;
bullets->bknown = otmp->bknown;
bullets->rknown = otmp->rknown;
bullets->sknown = otmp->sknown;
useupall(otmp);
bullets->owt = weight(bullets);
bullets = hold_another_object(bullets, u.uswallow ?
"Oops! %s out of your reach!" :
(Weightless ||
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(bullets, "slip")),
(const char *)0);
}break;
}
}
break;
case POWER_PACK:{
static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
struct obj *otmp = getobj(all_count, "charge");
if (!otmp) break;
if(otmp == obj){
if(obj->quan > 1) pline("That seems rather pointless.");
else pline("That seems rather difficult.");
}
You("press %s up against %s.", the(singular(obj,xname)), the(xname(otmp)));
recharge(otmp, obj->cursed ? -1 : (obj->blessed ? 1 : 0));
pline("%s is used up!",The(singular(obj,xname)));
if(obj->quan>1)
useup(obj);
else{
useup(obj);
obj = 0;
}
}break;
case LIGHTSABER:
case BEAMSWORD:
case DOUBLE_LIGHTSABER:
case ROD_OF_FORCE:
if (uwep != obj && !(u.twoweap && uswapwep == obj) && !wield_tool(obj, (const char *)0)) break;
/* Fall through - activate via use_lamp */
/* MRKR: dwarvish helms are mining helmets.
* They can be used as brass lanterns.
* From an idea posted to RGRN by "Dr Darth"
* Code by Malcom Ryan
*/
case DWARVISH_HELM:
case LANTERN_PLATE_MAIL:
case OIL_LAMP:
case MAGIC_LAMP:
case LANTERN:
use_lamp(obj);
break;
case POWER_ARMOR:
if(!(uarm && uarm == obj)){
You("must be wearing your power armor to turn it on.");
break;
}
use_lamp(obj);
break;
case POT_OIL:
light_cocktail(obj);
obj = 0; //May have been dealocated, just get rid of it
break;
case SHADOWLANDER_S_TORCH:
light_torch(obj);
break;
case MAGIC_TORCH:
light_torch(obj);
break;
case SUNROD:
light_torch(obj);
break;
case TORCH:
light_torch(obj);
break;
case EXPENSIVE_CAMERA:
res = use_camera(obj);
break;
case TOWEL:
res = use_towel(obj);
break;
case CRYSTAL_BALL:
res = use_crystal_ball(obj);
break;
case MAGIC_MARKER:
res = dowrite(obj);
break;
case TIN_OPENER:
if(!carrying(TIN)) {
You("have no tin to open.");
goto xit;
}
You("cannot open a tin without eating or discarding its contents.");
if(flags.verbose)
pline("In order to eat, use the 'e' command.");
if(obj != uwep)
pline("Opening the tin will be much easier if you wield the tin opener.");
goto xit;
case FIGURINE:
res = use_figurine(&obj);
break;
case CRYSTAL_SKULL:
res = use_crystal_skull(&obj);
break;
case EFFIGY:{
struct obj *curo;
if (Hallucination) You_feel("the tall leather doll take up your burdens!");
else You_feel("like someone is helping you.");
if(u.sealsActive&SEAL_MARIONETTE){
unbind(SEAL_MARIONETTE,TRUE);
}
for (curo = invent; curo; curo = curo->nobj) {
#ifdef GOLDOBJ
/* gold isn't subject to cursing and blessing */
if (curo->oclass == COIN_CLASS) continue;
#endif
if (curo->cursed) uncurse(curo);
}
if(Punished) unpunish();
if(Role_if(PM_ANACHRONOUNBINDER)){
u.sealsActive = 0;
u.sealCounts = 0;
The("spirits of the land no longer walk with you.");
}
/* also affects saddles */
if (u.usteed) {
curo = which_armor(u.usteed, W_SADDLE);
if (curo) uncurse(curo);
}
//Share your insanity
if(u.usanity < 100){
change_usanity((Insanity)/2, FALSE);
}
if(u.wimage >= 10){
struct monst *mtmp;
u.wimage = 0;
mtmp = makemon(&mons[PM_WEEPING_ANGEL], u.ux, u.uy, MM_ADJACENTOK|NO_MINVENT|MM_NOCOUNTBIRTH);
if(mtmp && HDoubt)
mtmp->mdoubt = TRUE;
if(Blind) pline("The effigy grows and turns to stone!");
else pline("The effigy becomes a weeping angel!");
} else if(u.umorgul){
int i = rnd(u.umorgul);
struct obj *frags;
u.umorgul -= i;
frags = mksobj(SHURIKEN, MKOBJ_NOINIT);
if(frags){
frags->quan = i;
add_oprop(frags, OPROP_LESSER_MORGW);
set_material_gm(frags, METAL);
curse(frags);
fix_object(frags);
pline("The effigy is pierced by %s!",
i==1 ? "a blade" : "blades");
frags = hold_another_object(frags, "You drop %s!",
doname(frags), (const char *)0); /*shouldn't merge, but may drop*/
}
if(u.umummyrot)
pline("The effigy crumbles to dust!");
else {
if(Blind) pline("The effigy bursts into flames!");
else pline("The effigy burns with sickly flames!");
}
} else if (u.umummyrot){
pline("The effigy crumbles to dust!");
} else if (u.uhpmod < -18){
if(Blind) pline("The effigy drips with a sticky liquid!");
else pline("The effigy is scored by wounds!");
} else {
if(Blind) pline("The effigy bursts into flames!");
else pline("The effigy burns with sickly flames!");
}
if(HDoubt){
make_doubtful(0L, TRUE);
}
u.wimage = 0; //Sub-critical images are removed anyway.
u.umummyrot = 0;
if (u.uhpmod < 0){
u.uhpmod /= 2; // we only print a message if it's a lot, but fix regardless
calc_total_maxhp();
}
if(obj->quan>1)
useup(obj);
else{
useup(obj);
obj = 0;
}
update_inventory();
} break;
case DOLL_OF_JUMPING:
case DOLL_OF_FRIENDSHIP:
case DOLL_OF_CHASTITY:
case DOLL_OF_CLEAVING:
case DOLL_OF_SATIATION:
case DOLL_OF_GOOD_HEALTH:
case DOLL_OF_FULL_HEALING:
case DOLL_OF_DESTRUCTION:
case DOLL_OF_MEMORY:
case DOLL_OF_BINDING:
case DOLL_OF_PRESERVATION:
case DOLL_OF_QUICK_DRAWING:
case DOLL_OF_WAND_CHARGING:
case DOLL_OF_STEALING:
case DOLL_OF_MOLLIFICATION:
case DOLL_OF_CLEAR_THINKING:
case DOLL_OF_MIND_BLASTING:
res = use_doll(obj);
break;
case DOLL_S_TEAR:
res = use_doll_tear(obj);
break;
case DILITHIUM_CRYSTAL:
if(Role_if(PM_ANACHRONONAUT) && !obj->oartifact)
res = use_dilithium(obj);
else {
pline("Sorry, I don't know how to use that.");
nomul(0, NULL);
return MOVE_CANCELLED;
}
break;
case HOLY_SYMBOL_OF_THE_BLACK_MOTHE:
return commune_with_goat();
break;
case PURIFIED_MIRROR:
if(u.silver_atten) return commune_with_silver_flame();
else res = use_mirror(&obj);
break;
case MISOTHEISTIC_PYRAMID:
case MISOTHEISTIC_FRAGMENT:
res = use_pyramid(obj);
break;
case DIMENSIONAL_LOCK:
res = use_dimensional_lock(obj);
break;
case CATAPSI_VORTEX:
res = use_vortex(obj);
break;
case ANTIMAGIC_RIFT:
res = use_rift(obj);
break;
case VITAL_SOULSTONE:
if (objects[obj->otyp].oc_name_known)
res = use_vital(obj);
else
use_stone(obj);
break;
case SPIRITUAL_SOULSTONE:
if (objects[obj->otyp].oc_name_known)
res = use_spiritual(obj);
else
use_stone(obj);
break;
case PRESERVATIVE_ENGINE:
res = res_engine_menu(obj);
break;
case ARMOR_SALVE:
res = use_armor_salve(obj);
break;
case MIST_PROJECTOR:
res = use_mist_projector(obj);
break;
case UNICORN_HORN:
use_unicorn_horn(obj);
break;
case FLUTE:
case MAGIC_FLUTE:
case TOOLED_HORN:
case FROST_HORN:
case FIRE_HORN:
case HARP:
case MAGIC_HARP:
case BUGLE:
case DRUM:
case DRUM_OF_EARTHQUAKE:
res = do_play_instrument(obj);
break;
case HORN_OF_PLENTY: /* not a musical instrument */
(void) hornoplenty(obj, FALSE);
break;
break;
case LAND_MINE:
case BEARTRAP:
use_trap(obj);
break;
case DROVEN_CLOAK:
if(obj->oartifact == ART_DARKWEAVER_S_CLOAK) res = use_darkweavers_cloak(obj);
else res = use_droven_cloak(&obj);
break;
case EILISTRAN_ARMOR:
res = use_eilistran_armor(&obj);
break;
case ROCK:
case FLINT:
case LUCKSTONE:
case LOADSTONE:
case TOUCHSTONE:
use_stone(obj);
break;
case SENSOR_PACK:
res = use_sensor(obj);
break;
case HYPOSPRAY:
res = use_hypospray(obj);
break;
case RAYGUN:
if(obj->altmode == AD_FIRE){
obj->altmode = AD_DEAD;
You("set %s to kill.", yname(obj));
} else if(obj->altmode == AD_DEAD){
obj->altmode = AD_DISN;
You("set %s to disintegrate.", yname(obj));
} else if(obj->altmode == AD_DISN){
obj->altmode = AD_SLEE;
You("set %s to stun.", yname(obj));
} else {
obj->altmode = AD_FIRE;
You("set %s to heat.", yname(obj));
}
res = MOVE_PARTIAL;
break;
case MASS_SHADOW_PISTOL:
res = use_massblaster(obj);
break;
case ARM_BLASTER:
case ASSAULT_RIFLE:
/* Switch between WP_MODE_SINGLE, WP_MODE_BURST and WP_MODE_AUTO */
if (obj->altmode == WP_MODE_AUTO) {
obj->altmode = WP_MODE_BURST;
} else if (obj->altmode == WP_MODE_BURST) {
obj->altmode = WP_MODE_SINGLE;
} else {
obj->altmode = WP_MODE_AUTO;
}
res = MOVE_PARTIAL;
You("switch %s to %s mode.", yname(obj),
((obj->altmode == WP_MODE_SINGLE) ? "semi-automatic" :
((obj->altmode == WP_MODE_BURST) ? "burst" :
"full automatic")));
break;
case BFG:
if (obj->altmode == WP_MODE_AUTO) obj-> altmode = WP_MODE_BURST;
else obj->altmode = WP_MODE_AUTO;
res = MOVE_PARTIAL;
You("switch %s to %s mode.", yname(obj),
(obj->altmode ? "burst" : "full automatic"));
break;
case AUTO_SHOTGUN:
case SUBMACHINE_GUN:
if (obj->altmode == WP_MODE_AUTO) obj-> altmode = WP_MODE_SINGLE;
else obj->altmode = WP_MODE_AUTO;
res = MOVE_PARTIAL;
You("switch %s to %s mode.", yname(obj),
(obj->altmode ? "semi-automatic" : "full automatic"));
break;
case FRAG_GRENADE:
case GAS_GRENADE:
if (!obj->oarmed) {
You("arm %s.", yname(obj));
arm_bomb(obj, TRUE);
res = MOVE_PARTIAL;
} else {
pline("It's already armed!");
res = MOVE_CANCELLED;
}
break;
case STICK_OF_DYNAMITE:
light_cocktail(obj);
break;
case CLOCKWORK_COMPONENT:
case SUBETHAIC_COMPONENT:
case HELLFIRE_COMPONENT:
case SCRAP:
res = doUseComponents(&obj);
break;
case UPGRADE_KIT:
res = doUseUpgradeKit(&obj);
check_loadout_trophy();
break;
case HYPERBOREAN_DIAL:
if(obj->ovar1_puzzle_steps < u.uhyperborean_steps){
pline("You are able to solve the current disk of the puzzle.");
obj->ovar1_puzzle_steps++;
if(obj->ovar1_puzzle_steps == 6){
pline("You have completed this puzzle as well.");
}
return MOVE_STANDARD;
}
if(obj->ovar1_puzzle_steps == 0){
pline("This strange mechanism has a number of freely rotating disks and pegs that pop up and down.");
if(ACURR(A_INT) > 13)
pline("It seems to be some sort of puzzle, but you aren't able to make any progress!");
}
else if(obj->ovar1_puzzle_steps == 1){
pline("While you were sleeping, you seem to have solved part of the puzzle.");
pline("One ring has locked into place, and a hexagonal peg projects from the front face.");
}
else if(obj->ovar1_puzzle_steps < 6){
pline("Your sleeping mind has completed %ld rings of the puzzle.", obj->ovar1_puzzle_steps);
}
else {
pline("The puzzle is complete. All rings have locked into place, and six hexagonal pegs project from the front.");
}
return MOVE_CANCELLED;
break;
default:
/* Pole-weapons can strike at a distance */
if (is_pole(obj)) {
res = use_pole(obj);
break;
} else if (is_pick(obj) || is_axe(obj)) {
res = use_pick_axe(obj);
break;
}
else if(
(obj->oartifact == ART_SKY_REFLECTED && carrying_art(ART_SILVER_SKY)) ||
(obj->oartifact == ART_SILVER_SKY && carrying_art(ART_SKY_REFLECTED))
){
res = merge_skies(&obj);
break;
}
pline("Sorry, I don't know how to use that.");
xit:
nomul(0, NULL);
return MOVE_CANCELLED;
}
if(!(res == MOVE_CANCELLED) && !waslabile && obj && obj->oartifact) arti_speak(obj);
xit2:
nomul(0, NULL);
return res;
}
/* Keep track of unfixable troubles for purposes of messages saying you feel
* great.
*/
int
unfixable_trouble_count(boolean is_horn)
{
int unfixable_trbl = 0;
if (Stoned) unfixable_trbl++;
if (Golded) unfixable_trbl++;
if (Strangled) unfixable_trbl++;
if (Panicking) unfixable_trbl++;
if (StumbleBlind) unfixable_trbl++;
if (StaggerShock) unfixable_trbl++;
if (Babble) unfixable_trbl++;
if (Screaming) unfixable_trbl++;
if (FaintingFits) unfixable_trbl++;
if (Wounded_legs
&& !u.usteed
) unfixable_trbl++;
if (Slimed) unfixable_trbl++;
if (FrozenAir) unfixable_trbl++;
if (BloodDrown) unfixable_trbl++;
/* lycanthropy is not desirable, but it doesn't actually make you feel
bad */
/* we'll assume that intrinsic stunning from being a bat/stalker
doesn't make you feel bad */
if (!is_horn) {
if (Confusion) unfixable_trbl++;
if (Sick) unfixable_trbl++;
if (HHallucination) unfixable_trbl++;
if (Vomiting) unfixable_trbl++;
if (HStun) unfixable_trbl++;
}
return unfixable_trbl;
}
int
dotrephination_menu(void)
{
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Extract what?");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
incntlet = 'a';
if (u.thoughts&CLOCKWISE_METAMORPHOSIS){
Sprintf(buf, "Extract clockwise gyre");
any.a_int = CLOCKWISE_METAMORPHOSIS_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&ANTI_CLOCKWISE_METAMORPHOSIS){
Sprintf(buf, "Extract anti-clockwise gyre");
any.a_int = ANTI_CLOCKWISE_METAMORPHOSIS_G; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&ARCANE_BULWARK){
Sprintf(buf, "Extract memory of a sparking lake-shore");
any.a_int = SPARKLING_LAKE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&DISSIPATING_BULWARK){
Sprintf(buf, "Extract memory of a pure lake-shore");
any.a_int = FADING_LAKE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&SMOLDERING_BULWARK){
Sprintf(buf, "Extract memory of embers drowning in still water");
any.a_int = SMOKING_LAKE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&FROSTED_BULWARK){
Sprintf(buf, "Extract memory of snowflakes on a lake");
any.a_int = FROSTED_LAKE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&BLOOD_RAPTURE){
Sprintf(buf, "Extract memory of blood-mist rainbows");
any.a_int = RAPTUROUS_EYE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&CLAWMARK){
Sprintf(buf, "Extract memory of clawmarks");
any.a_int = CLAWMARK_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&CLEAR_DEEPS){
Sprintf(buf, "Extract the deep blue waters");
any.a_int = CLEAR_SEA_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&DEEP_SEA){
Sprintf(buf, "Extract the pitch-black waters");
any.a_int = DEEP_SEA_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&TRANSPARENT_SEA){
Sprintf(buf, "Extract the perfectly clear sea");
any.a_int = HIDDEN_SEA_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&COMMUNION){
Sprintf(buf, "Extract memory of the strange minister's sermon");
any.a_int = COMMUNION_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&CORRUPTION){
Sprintf(buf, "Extract the bloody tears");
any.a_int = CORRUPTION_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&EYE_THOUGHT){
Sprintf(buf, "Extract the writhing eyes");
any.a_int = EYE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&FORMLESS_VOICE){
Sprintf(buf, "Extract sound of the great voice");
any.a_int = FORMLESS_VOICE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&GUIDANCE){
Sprintf(buf, "Extract the sight of the dancing sprites");
any.a_int = GUIDANCE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&IMPURITY){
Sprintf(buf, "Extract the red millipedes and their filth");
any.a_int = IMPURITY_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&MOON){
Sprintf(buf, "Extract memory of the face of the moon");
any.a_int = MOON_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&WRITHE){
Sprintf(buf, "Extract subtle mucus from your brain");
any.a_int = WRITHE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&RADIANCE){
Sprintf(buf, "Extract the golden pyramid");
any.a_int = RADIANCE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&BEASTS_EMBRACE){
Sprintf(buf, "Extract the bestial figure");
any.a_int = BEAST_S_EMBRACE_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
if (u.thoughts&SIGHT){
Sprintf(buf, "Extract the recursive eye");
any.a_int = ORRERY_GLYPH; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
}
end_menu(tmpwin, "Pick thought to extract");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n > 0){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
static int
dotrephination_options(void)
{
winid tmpwin;
int n, how;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Use kit on what?");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
incntlet = 'a';
Sprintf(buf, "Your brain");
any.a_int = TREPH_THOUGHTS; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
Sprintf(buf, "Your skulls");
any.a_int = TREPH_CRYSTALS; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet++;
end_menu(tmpwin, "Pick patient");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n > 0){
int picked = selected[0].item.a_int;
free(selected);
return picked;
}
return 0;
}
//Returns 0 if this is the first time its called this round, 1 otherwise.
int
partial_action(void)
{
int res = (moves == u.last_used_move) &&
(youmonst.movement == u.last_used_movement);
u.last_used_move = moves;
u.last_used_movement = youmonst.movement;
return res;
}
//Returns returns 1 if the partial_action() has been used this round.
int
check_partial_action(void)
{
return ((moves == u.last_used_move) &&
(youmonst.movement == u.last_used_movement));
}
/*apply.c*/