Merge branch 'NetHack-3.7' of https://rodney.nethack.org:20040/git/NHsource into NetHack-3.7
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.369 $ $NHDT-Date: 1606781767 2020/12/01 00:16:07 $
|
||||
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.375 $ $NHDT-Date: 1607200174 2020/12/05 20:29:34 $
|
||||
|
||||
General Fixes and Modified Features
|
||||
-----------------------------------
|
||||
@@ -315,7 +315,11 @@ try to fix message sequencing for tame golems that "roast/rot/rust in peace"
|
||||
autodescribe when moving the cursor was erroneously honoring MSGTYPE=stop
|
||||
and potentially delivering sounds
|
||||
reduce the number of "seeXYZ" commands by renaming some: #seenv -> #wizseenv,
|
||||
#seespells -> #showspells, and #seetrap -> #showtrap
|
||||
#seegold -> #showgold, #seespells -> #showspells, #seetrap -> #showtrap
|
||||
when saving while punished or game ends while punished, handling for ball and
|
||||
chain might access freed memory with unpredictable consequences
|
||||
brown pudding monster hitting another monster with decay attack corroded armor
|
||||
instead of rotting it
|
||||
|
||||
|
||||
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
|
||||
@@ -505,6 +509,10 @@ Qt: don't get stuck in a loop after choosing "play" while the character name
|
||||
field is empty in the character selection widget
|
||||
Qt: when a new message is issued, pan the message window to its left edge if
|
||||
player panned it horizontally then didn't manually scroll it back
|
||||
Qt: there was no way to enter extended command "#version" by typing; command
|
||||
name matching was waiting to disambiguate it from "#versionshort"
|
||||
and the only way to that was to type #version<return> but <return>
|
||||
explicitly triggered rejection, cancelling '#' processing
|
||||
Qt: {maybe just Qt+OSX:} when viewing a text window ('V' to look at 'history'
|
||||
for instance), clicking on [Search], entering a search target in the
|
||||
resulting popup and clicking on [Okay] or typing <return>, the text
|
||||
@@ -632,6 +640,7 @@ render the color names in the corresponding color when using the pick-a-color
|
||||
reading blessed scroll of teleportation confers one-shot teleport control
|
||||
mild zombie apocalypse
|
||||
list lamps and lanterns in charging prompt
|
||||
let tourists read conical hats
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific New Features
|
||||
@@ -742,5 +751,7 @@ rework stairs structure into a linked list
|
||||
move 'restoring' to the program_state struct; add corresponding 'saving';
|
||||
both used to enforce no updating of status lines or of persistent
|
||||
inventory when the relevant activity is in progress
|
||||
unify special attack damages from separate you-hit-monster, monster-hits-you,
|
||||
and monster-hits-monster into functions by damage type
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 decl.h $NHDT-Date: 1606765210 2020/11/30 19:40:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.246 $ */
|
||||
/* NetHack 3.7 decl.h $NHDT-Date: 1606919254 2020/12/02 14:27:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.247 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Michael Allison, 2007. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -1103,6 +1103,8 @@ struct instance_globals {
|
||||
boolean havestate;
|
||||
unsigned ustuck_id; /* need to preserve during save */
|
||||
unsigned usteed_id; /* need to preserve during save */
|
||||
struct obj *looseball; /* track uball during save and... */
|
||||
struct obj *loosechain; /* track uchain since saving might free it */
|
||||
|
||||
/* shk.c */
|
||||
/* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 extern.h $NHDT-Date: 1606343573 2020/11/25 22:32:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.882 $ */
|
||||
/* NetHack 3.7 extern.h $NHDT-Date: 1606919254 2020/12/02 14:27:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.886 $ */
|
||||
/* Copyright (c) Steve Creps, 1988. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -1282,6 +1282,7 @@ E void FDECL(rustm, (struct monst *, struct obj *));
|
||||
|
||||
/* ### mhitu.c ### */
|
||||
|
||||
E void FDECL(hitmsg, (struct monst *, struct attack *));
|
||||
E const char *FDECL(mpoisons_subj, (struct monst *, struct attack *));
|
||||
E void NDECL(u_slow_down);
|
||||
E struct monst *NDECL(cloneu);
|
||||
@@ -1289,6 +1290,8 @@ E void FDECL(expels, (struct monst *, struct permonst *, BOOLEAN_P));
|
||||
E struct attack *FDECL(getmattk, (struct monst *, struct monst *,
|
||||
int, int *, struct attack *));
|
||||
E int FDECL(mattacku, (struct monst *));
|
||||
boolean FDECL(diseasemu, (struct permonst *));
|
||||
boolean FDECL(u_slip_free, (struct monst *, struct attack *));
|
||||
E int FDECL(magic_negation, (struct monst *));
|
||||
E boolean NDECL(gulp_blnd_check);
|
||||
E int FDECL(gazemu, (struct monst *, struct attack *));
|
||||
@@ -2754,9 +2757,51 @@ E boolean FDECL(attack, (struct monst *));
|
||||
E boolean FDECL(hmon, (struct monst *, struct obj *, int, int));
|
||||
E boolean FDECL(shade_miss, (struct monst *, struct monst *, struct obj *,
|
||||
BOOLEAN_P, BOOLEAN_P));
|
||||
E void FDECL(mhitm_ad_rust, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_corr, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_dcay, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_dren, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_drli, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_fire, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_cold, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_elec, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_acid, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_sgld, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_tlpt, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_blnd, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_curs, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_drst, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_drin, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_stck, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_wrap, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_plys, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_slee, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_slim, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_ench, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_slow, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_conf, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_poly, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_famn, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_pest, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_deth, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_halu, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_phys, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_ston, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_were, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_heal, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_stun, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_legs, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_dgst, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_samu, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_dise, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_sedu, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_ad_ssex, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E void FDECL(mhitm_adtyping, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E boolean FDECL(do_stone_u, (struct monst *));
|
||||
E void FDECL(do_stone_mon, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
|
||||
E int FDECL(damageum, (struct monst *, struct attack *, int));
|
||||
E void FDECL(missum, (struct monst *, struct attack *, BOOLEAN_P));
|
||||
E int FDECL(passive, (struct monst *, struct obj *, BOOLEAN_P, int,
|
||||
E int FDECL(passive, (struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P,
|
||||
UCHAR_P, BOOLEAN_P));
|
||||
E void FDECL(passive_obj, (struct monst *, struct obj *, struct attack *));
|
||||
E void FDECL(stumble_onto_mimic, (struct monst *));
|
||||
@@ -3122,6 +3167,7 @@ E void FDECL(flip_worm_segs_horizontal, (struct monst *, int, int));
|
||||
|
||||
E void FDECL(setworn, (struct obj *, long));
|
||||
E void FDECL(setnotworn, (struct obj *));
|
||||
E void NDECL(allunworn);
|
||||
E struct obj *FDECL(wearmask_to_obj, (long));
|
||||
E long FDECL(wearslot, (struct obj *));
|
||||
E void FDECL(mon_set_minvis, (struct monst *));
|
||||
|
||||
@@ -86,6 +86,15 @@
|
||||
#define AD_SAMU 252 /* hits, may steal Amulet (Wizard) */
|
||||
#define AD_CURS 253 /* random curse (ex. gremlin) */
|
||||
|
||||
struct mhitm_data {
|
||||
int damage;
|
||||
int hitflags; /* MM_DEF_DIED | MM_AGR_DIED | ... */
|
||||
boolean done;
|
||||
boolean permdmg;
|
||||
int specialdmg;
|
||||
int dieroll;
|
||||
};
|
||||
|
||||
/*
|
||||
* Monster to monster attacks. When a monster attacks another (mattackm),
|
||||
* any or all of the following can be returned. See mattackm() for more
|
||||
@@ -95,5 +104,6 @@
|
||||
#define MM_HIT 0x1 /* aggressor hit defender */
|
||||
#define MM_DEF_DIED 0x2 /* defender died */
|
||||
#define MM_AGR_DIED 0x4 /* aggressor died */
|
||||
#define MM_AGR_DONE 0x8 /* aggressor is done with their turn */
|
||||
|
||||
#endif /* MONATTK_H */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Incrementing EDITLEVEL can be used to force invalidation of old bones
|
||||
* and save files.
|
||||
*/
|
||||
#define EDITLEVEL 27
|
||||
#define EDITLEVEL 28
|
||||
|
||||
/*
|
||||
* Development status possibilities.
|
||||
|
||||
16
src/cmd.c
16
src/cmd.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 cmd.c $NHDT-Date: 1606781767 2020/12/01 00:16:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.426 $ */
|
||||
/* NetHack 3.7 cmd.c $NHDT-Date: 1607079461 2020/12/04 10:57:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.427 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2013. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -1873,26 +1873,29 @@ struct ext_func_tab extcmdlist[] = {
|
||||
dopramulet, IFBURIED },
|
||||
{ ARMOR_SYM, "seearmor", "show the armor currently worn",
|
||||
doprarm, IFBURIED },
|
||||
{ GOLD_SYM, "seegold", "count your gold", doprgold, IFBURIED },
|
||||
{ RING_SYM, "seerings", "show the ring(s) currently worn",
|
||||
doprring, IFBURIED },
|
||||
{ TOOL_SYM, "seetools", "show the tools currently in use",
|
||||
doprtool, IFBURIED },
|
||||
{ WEAPON_SYM, "seeweapon", "show the weapon currently wielded",
|
||||
doprwep, IFBURIED },
|
||||
{ '!', "shell", "do a shell escape",
|
||||
{ '!', "shell", "leave game to enter a sub-shell ('exit' to come back)",
|
||||
dosh_core, IFBURIED | GENERALCMD
|
||||
#ifndef SHELL
|
||||
| CMD_NOT_AVAILABLE
|
||||
#endif /* SHELL */
|
||||
},
|
||||
/* $ is like ),=,&c but is not included with *, so not called "seegold" */
|
||||
{ GOLD_SYM, "showgold", "show gold, possibly shop credit or debt",
|
||||
doprgold, IFBURIED },
|
||||
{ SPBOOK_SYM, "showspells", "list and reorder known spells",
|
||||
dovspell, IFBURIED },
|
||||
{ '^', "showtrap", "show the type of adjacent trap", doidtrap, IFBURIED },
|
||||
{ '^', "showtrap", "describe an adjacent, discovered trap",
|
||||
doidtrap, IFBURIED },
|
||||
{ M('s'), "sit", "sit down", dosit, AUTOCOMPLETE },
|
||||
{ '\0', "stats", "show memory statistics",
|
||||
wiz_show_stats, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
|
||||
{ C('z'), "suspend", "suspend the game",
|
||||
{ C('z'), "suspend", "push game to background ('fg' to come back)",
|
||||
dosuspend_core, IFBURIED | GENERALCMD
|
||||
#ifndef SUSPEND
|
||||
| CMD_NOT_AVAILABLE
|
||||
@@ -1922,7 +1925,8 @@ struct ext_func_tab extcmdlist[] = {
|
||||
{ M('v'), "version",
|
||||
"list compile time options for this version of NetHack",
|
||||
doextversion, IFBURIED | AUTOCOMPLETE | GENERALCMD },
|
||||
{ 'v', "versionshort", "show version", doversion, IFBURIED | GENERALCMD },
|
||||
{ 'v', "versionshort", "show version and date/time program was built",
|
||||
doversion, IFBURIED | GENERALCMD },
|
||||
{ '\0', "vision", "show vision array",
|
||||
wiz_show_vision, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
|
||||
{ '.', "wait", "rest one move while doing nothing",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 decl.c $NHDT-Date: 1600468453 2020/09/18 22:34:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.218 $ */
|
||||
/* NetHack 3.7 decl.c $NHDT-Date: 1606919256 2020/12/02 14:27:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.221 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Michael Allison, 2009. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -611,6 +611,8 @@ const struct instance_globals g_init = {
|
||||
TRUE, /* havestate*/
|
||||
0, /* ustuck_id */
|
||||
0, /* usteed_id */
|
||||
(struct obj *) 0, /* looseball */
|
||||
(struct obj *) 0, /* loosechain */
|
||||
|
||||
/* shk.c */
|
||||
'a', /* sell_response */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 display.c $NHDT-Date: 1597700875 2020/08/17 21:47:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.136 $ */
|
||||
/* NetHack 3.7 display.c $NHDT-Date: 1606919261 2020/12/02 14:27:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.139 $ */
|
||||
/* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
|
||||
/* and Dave Cohrs, 1990. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -1691,6 +1691,10 @@ int cursor_on_u;
|
||||
static int delay_flushing = 0;
|
||||
register int x, y;
|
||||
|
||||
/* 3.7: don't update map, status, or perm_invent during save/restore */
|
||||
if (g.program_state.saving || g.program_state.restoring)
|
||||
return;
|
||||
|
||||
if (cursor_on_u == -1)
|
||||
delay_flushing = !delay_flushing;
|
||||
if (delay_flushing)
|
||||
|
||||
29
src/dokick.c
29
src/dokick.c
@@ -18,7 +18,7 @@ static void FDECL(kick_monster, (struct monst *, XCHAR_P, XCHAR_P));
|
||||
static int FDECL(kick_object, (XCHAR_P, XCHAR_P, char *));
|
||||
static int FDECL(really_kick_object, (XCHAR_P, XCHAR_P));
|
||||
static char *FDECL(kickstr, (char *, const char *));
|
||||
static void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long));
|
||||
static void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, BOOLEAN_P, long));
|
||||
static void FDECL(drop_to, (coord *, SCHAR_P, XCHAR_P, XCHAR_P));
|
||||
|
||||
static const char kick_passes_thru[] = "kick passes harmlessly through";
|
||||
@@ -1510,7 +1510,7 @@ boolean shop_floor_obj;
|
||||
coord cc;
|
||||
struct obj *obj;
|
||||
struct trap *t;
|
||||
boolean nodrop, unpaid, container, impact = FALSE;
|
||||
boolean nodrop, unpaid, container, impact = FALSE, chainthere = FALSE;
|
||||
long n = 0L;
|
||||
|
||||
if (!otmp)
|
||||
@@ -1530,9 +1530,12 @@ boolean shop_floor_obj;
|
||||
unpaid = is_unpaid(otmp);
|
||||
|
||||
if (OBJ_AT(x, y)) {
|
||||
for (obj = g.level.objects[x][y]; obj; obj = obj->nexthere)
|
||||
if (obj != otmp)
|
||||
for (obj = g.level.objects[x][y]; obj; obj = obj->nexthere) {
|
||||
if (obj == uchain)
|
||||
chainthere = TRUE;
|
||||
else if (obj != otmp)
|
||||
n += obj->quan;
|
||||
}
|
||||
if (n)
|
||||
impact = TRUE;
|
||||
}
|
||||
@@ -1546,7 +1549,7 @@ boolean shop_floor_obj;
|
||||
}
|
||||
|
||||
if (cansee(x, y))
|
||||
otransit_msg(otmp, nodrop, n);
|
||||
otransit_msg(otmp, nodrop, chainthere, n);
|
||||
|
||||
if (nodrop) {
|
||||
if (impact)
|
||||
@@ -1665,7 +1668,7 @@ boolean near_hero;
|
||||
case MIGR_SSTAIRS:
|
||||
if ((stway = stairway_find_from(&fromdlev, isladder)) != 0) {
|
||||
nx = stway->sx;
|
||||
nx = stway->sy;
|
||||
ny = stway->sy;
|
||||
}
|
||||
break;
|
||||
case MIGR_WITH_HERO:
|
||||
@@ -1766,9 +1769,9 @@ unsigned long deliverflags;
|
||||
}
|
||||
|
||||
static void
|
||||
otransit_msg(otmp, nodrop, num)
|
||||
otransit_msg(otmp, nodrop, chainthere, num)
|
||||
register struct obj *otmp;
|
||||
register boolean nodrop;
|
||||
boolean nodrop, chainthere;
|
||||
long num;
|
||||
{
|
||||
char *optr = 0, obuf[BUFSZ], xbuf[BUFSZ];
|
||||
@@ -1782,11 +1785,15 @@ long num;
|
||||
}
|
||||
Strcpy(obuf, optr);
|
||||
|
||||
if (num) { /* means: other objects are impacted */
|
||||
if (num || chainthere) {
|
||||
/* As of 3.6.2: use a separate buffer for the suffix to avoid risk of
|
||||
overrunning obuf[] (let pline() handle truncation if necessary) */
|
||||
Sprintf(xbuf, " %s %s object%s", otense(otmp, "hit"),
|
||||
(num == 1L) ? "another" : "other", (num > 1L) ? "s" : "");
|
||||
if (num) { /* means: other objects are impacted */
|
||||
Sprintf(xbuf, " %s %s object%s", otense(otmp, "hit"),
|
||||
(num == 1L) ? "another" : "other", (num > 1L) ? "s" : "");
|
||||
} else { /* chain-only msg */
|
||||
Sprintf(xbuf, " %s your chain", otense(otmp, "rattle"));
|
||||
}
|
||||
if (nodrop)
|
||||
Sprintf(eos(xbuf), ".");
|
||||
else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 dothrow.c $NHDT-Date: 1606343578 2020/11/25 22:32:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.190 $ */
|
||||
/* NetHack 3.7 dothrow.c $NHDT-Date: 1607200366 2020/12/05 20:32:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.191 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2013. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -23,8 +23,9 @@ static boolean FDECL(mhurtle_step, (genericptr_t, int, int));
|
||||
static NEARDATA const char toss_objs[] = { ALLOW_COUNT, COIN_CLASS,
|
||||
ALL_CLASSES, WEAPON_CLASS, 0 };
|
||||
/* different default choices when wielding a sling (gold must be included) */
|
||||
static NEARDATA const char bullets[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES,
|
||||
GEM_CLASS, 0 };
|
||||
static NEARDATA const char t_bullets[] = {
|
||||
ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0
|
||||
};
|
||||
|
||||
/* g.thrownobj (decl.c) tracks an object until it lands */
|
||||
|
||||
@@ -295,7 +296,7 @@ dothrow()
|
||||
if (!ok_to_throw(&shotlimit))
|
||||
return 0;
|
||||
|
||||
obj = getobj(uslinging() ? bullets : toss_objs, "throw");
|
||||
obj = getobj(uslinging() ? t_bullets : toss_objs, "throw");
|
||||
/* it is also possible to throw food */
|
||||
/* (or jewels, or iron balls... ) */
|
||||
|
||||
@@ -407,7 +408,7 @@ dofire()
|
||||
use direction of previous throw as getobj()'s choice here */
|
||||
g.in_doagain = 0;
|
||||
/* choose something from inventory, then usually quiver it */
|
||||
obj = getobj(uslinging() ? bullets : toss_objs, "throw");
|
||||
obj = getobj(uslinging() ? t_bullets : toss_objs, "throw");
|
||||
/* Q command doesn't allow gold in quiver */
|
||||
if (obj && !obj->owornmask && obj->oclass != COIN_CLASS)
|
||||
setuqwep(obj); /* demi-autoquiver */
|
||||
|
||||
628
src/mhitm.c
628
src/mhitm.c
@@ -267,6 +267,7 @@ boolean quietly;
|
||||
* / / /
|
||||
* x x x
|
||||
*
|
||||
* 0x8 MM_AGR_DONE
|
||||
* 0x4 MM_AGR_DIED
|
||||
* 0x2 MM_DEF_DIED
|
||||
* 0x1 MM_HIT
|
||||
@@ -367,7 +368,7 @@ register struct monst *magr, *mdef;
|
||||
case AT_WEAP: /* "hand to hand" attacks */
|
||||
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) {
|
||||
/* D: Do a ranged attack here! */
|
||||
strike = thrwmm(magr, mdef);
|
||||
strike = (thrwmm(magr, mdef) == MM_MISS) ? 0 : 1;
|
||||
if (strike)
|
||||
/* don't really know if we hit or not; pretend we did */
|
||||
res[i] |= MM_HIT;
|
||||
@@ -380,7 +381,7 @@ register struct monst *magr, *mdef;
|
||||
if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
|
||||
magr->weapon_check = NEED_HTH_WEAPON;
|
||||
if (mon_wield_item(magr) != 0)
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
}
|
||||
possibly_unwield(magr, FALSE);
|
||||
if ((mwep = MON_WEP(magr)) != 0) {
|
||||
@@ -489,7 +490,7 @@ register struct monst *magr, *mdef;
|
||||
|
||||
case AT_BREA:
|
||||
if (!monnear(magr, mdef->mx, mdef->my)) {
|
||||
strike = breamm(magr, mattk, mdef);
|
||||
strike = (breamm(magr, mattk, mdef) == MM_MISS) ? 0 : 1;
|
||||
|
||||
/* We don't really know if we hit or not; pretend we did. */
|
||||
if (strike)
|
||||
@@ -505,7 +506,7 @@ register struct monst *magr, *mdef;
|
||||
|
||||
case AT_SPIT:
|
||||
if (!monnear(magr, mdef->mx, mdef->my)) {
|
||||
strike = spitmm(magr, mattk, mdef);
|
||||
strike = (spitmm(magr, mattk, mdef) == MM_MISS) ? 0 : 1;
|
||||
|
||||
/* We don't really know if we hit or not; pretend we did. */
|
||||
if (strike)
|
||||
@@ -855,13 +856,16 @@ struct attack *mattk;
|
||||
struct obj *mwep;
|
||||
int dieroll;
|
||||
{
|
||||
struct obj *obj;
|
||||
char buf[BUFSZ];
|
||||
struct permonst *pa = magr->data, *pd = mdef->data;
|
||||
int armpro, num,
|
||||
tmp = d((int) mattk->damn, (int) mattk->damd),
|
||||
res = MM_MISS;
|
||||
int armpro;
|
||||
boolean cancelled;
|
||||
struct mhitm_data mhm;
|
||||
mhm.damage = d((int) mattk->damn, (int) mattk->damd);
|
||||
mhm.hitflags = MM_MISS;
|
||||
mhm.permdmg = 0;
|
||||
mhm.specialdmg = 0;
|
||||
mhm.dieroll = dieroll;
|
||||
mhm.done = FALSE;
|
||||
|
||||
if ((touch_petrifies(pd) /* or flesh_petrifies() */
|
||||
|| (mattk->adtyp == AD_DGST && pd == &mons[PM_MEDUSA]))
|
||||
@@ -894,593 +898,14 @@ int dieroll;
|
||||
armpro = magic_negation(mdef);
|
||||
cancelled = magr->mcan || !(rn2(10) >= 3 * armpro);
|
||||
|
||||
switch (mattk->adtyp) {
|
||||
case AD_DGST:
|
||||
/* eating a Rider or its corpse is fatal */
|
||||
if (is_rider(pd)) {
|
||||
if (g.vis && canseemon(magr))
|
||||
pline("%s %s!", Monnam(magr),
|
||||
(pd == &mons[PM_FAMINE])
|
||||
? "belches feebly, shrivels up and dies"
|
||||
: (pd == &mons[PM_PESTILENCE])
|
||||
? "coughs spasmodically and collapses"
|
||||
: "vomits violently and drops dead");
|
||||
mondied(magr);
|
||||
if (!DEADMONSTER(magr))
|
||||
return 0; /* lifesaved */
|
||||
else if (magr->mtame && !g.vis)
|
||||
You(brief_feeling, "queasy");
|
||||
return MM_AGR_DIED;
|
||||
}
|
||||
if (flags.verbose && !Deaf)
|
||||
verbalize("Burrrrp!");
|
||||
tmp = mdef->mhp;
|
||||
/* Use up amulet of life saving */
|
||||
if ((obj = mlifesaver(mdef)) != 0)
|
||||
m_useup(mdef, obj);
|
||||
mhitm_adtyping(magr, mattk, mdef, &mhm);
|
||||
if (mhm.done)
|
||||
return mhm.hitflags;
|
||||
|
||||
/* Is a corpse for nutrition possible? It may kill magr */
|
||||
if (!corpse_chance(mdef, magr, TRUE) || DEADMONSTER(magr))
|
||||
break;
|
||||
if (!mhm.damage)
|
||||
return mhm.hitflags;
|
||||
|
||||
/* Pets get nutrition from swallowing monster whole.
|
||||
* No nutrition from G_NOCORPSE monster, eg, undead.
|
||||
* DGST monsters don't die from undead corpses
|
||||
*/
|
||||
num = monsndx(pd);
|
||||
if (magr->mtame && !magr->isminion
|
||||
&& !(g.mvitals[num].mvflags & G_NOCORPSE)) {
|
||||
struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE);
|
||||
int nutrit;
|
||||
|
||||
set_corpsenm(virtualcorpse, num);
|
||||
nutrit = dog_nutrition(magr, virtualcorpse);
|
||||
dealloc_obj(virtualcorpse);
|
||||
|
||||
/* only 50% nutrition, 25% of normal eating time */
|
||||
if (magr->meating > 1)
|
||||
magr->meating = (magr->meating + 3) / 4;
|
||||
if (nutrit > 1)
|
||||
nutrit /= 2;
|
||||
EDOG(magr)->hungrytime += nutrit;
|
||||
}
|
||||
break;
|
||||
case AD_STUN:
|
||||
if (magr->mcan)
|
||||
break;
|
||||
if (canseemon(mdef))
|
||||
pline("%s %s for a moment.", Monnam(mdef),
|
||||
makeplural(stagger(pd, "stagger")));
|
||||
mdef->mstun = 1;
|
||||
goto physical;
|
||||
case AD_LEGS:
|
||||
if (magr->mcan) {
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
goto physical;
|
||||
case AD_WERE:
|
||||
case AD_HEAL:
|
||||
case AD_PHYS:
|
||||
physical:
|
||||
if (mattk->aatyp != AT_WEAP && mattk->aatyp != AT_CLAW)
|
||||
mwep = 0;
|
||||
|
||||
if (shade_miss(magr, mdef, mwep, FALSE, TRUE)) {
|
||||
tmp = 0;
|
||||
} else if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
|
||||
/* [no 'kicking boots' check needed; monsters with kick attacks
|
||||
can't wear boots and monsters that wear boots don't kick] */
|
||||
tmp = 0;
|
||||
} else if (mwep) { /* non-Null 'mwep' implies AT_WEAP || AT_CLAW */
|
||||
struct obj *marmg;
|
||||
|
||||
if (mwep->otyp == CORPSE
|
||||
&& touch_petrifies(&mons[mwep->corpsenm]))
|
||||
goto do_stone;
|
||||
|
||||
tmp += dmgval(mwep, mdef);
|
||||
if ((marmg = which_armor(magr, W_ARMG)) != 0
|
||||
&& marmg->otyp == GAUNTLETS_OF_POWER)
|
||||
tmp += rn1(4, 3); /* 3..6 */
|
||||
if (tmp < 1) /* is this necessary? mhitu.c has it... */
|
||||
tmp = 1;
|
||||
if (mwep->oartifact) {
|
||||
/* when magr's weapon is an artifact, caller suppressed its
|
||||
usual 'hit' message in case artifact_hit() delivers one;
|
||||
now we'll know and might need to deliver skipped message
|
||||
(note: if there's no message there'll be no auxilliary
|
||||
damage so the message here isn't coming too late) */
|
||||
if (!artifact_hit(magr, mdef, mwep, &tmp, dieroll)) {
|
||||
if (g.vis)
|
||||
pline("%s hits %s.", Monnam(magr),
|
||||
mon_nam_too(mdef, magr));
|
||||
}
|
||||
/* artifact_hit updates 'tmp' but doesn't inflict any
|
||||
damage; however, it might cause carried items to be
|
||||
destroyed and they might do so */
|
||||
if (DEADMONSTER(mdef))
|
||||
return (MM_DEF_DIED
|
||||
| (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
}
|
||||
if (tmp)
|
||||
rustm(mdef, mwep);
|
||||
} else if (pa == &mons[PM_PURPLE_WORM] && pd == &mons[PM_SHRIEKER]) {
|
||||
/* hack to enhance mm_aggression(); we don't want purple
|
||||
worm's bite attack to kill a shrieker because then it
|
||||
won't swallow the corpse; but if the target survives,
|
||||
the subsequent engulf attack should accomplish that */
|
||||
if (tmp >= mdef->mhp && mdef->mhp > 1)
|
||||
tmp = mdef->mhp - 1;
|
||||
}
|
||||
break;
|
||||
case AD_FIRE:
|
||||
if (cancelled) {
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
|
||||
if (completelyburns(pd)) { /* paper golem or straw golem */
|
||||
/* note: the life-saved case is hypothetical because
|
||||
life-saving doesn't work for golems */
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s %s!", Monnam(mdef),
|
||||
!mlifesaver(mdef) ? "burns completely"
|
||||
: "is totally engulfed in flames");
|
||||
monkilled(mdef, (char *) 0, AD_FIRE);
|
||||
if (!DEADMONSTER(mdef))
|
||||
return 0;
|
||||
return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
}
|
||||
tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
|
||||
tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
|
||||
if (resists_fire(mdef)) {
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline_The("fire doesn't seem to burn %s!", mon_nam(mdef));
|
||||
shieldeff(mdef->mx, mdef->my);
|
||||
golemeffects(mdef, AD_FIRE, tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
/* only potions damage resistant players in destroy_item */
|
||||
tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
|
||||
ignite_items(mdef->minvent);
|
||||
break;
|
||||
case AD_COLD:
|
||||
if (cancelled) {
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s is covered in frost!", Monnam(mdef));
|
||||
if (resists_cold(mdef)) {
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline_The("frost doesn't seem to chill %s!", mon_nam(mdef));
|
||||
shieldeff(mdef->mx, mdef->my);
|
||||
golemeffects(mdef, AD_COLD, tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
|
||||
break;
|
||||
case AD_ELEC:
|
||||
if (cancelled) {
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s gets zapped!", Monnam(mdef));
|
||||
tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
|
||||
if (resists_elec(mdef)) {
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline_The("zap doesn't shock %s!", mon_nam(mdef));
|
||||
shieldeff(mdef->mx, mdef->my);
|
||||
golemeffects(mdef, AD_ELEC, tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
/* only rings damage resistant players in destroy_item */
|
||||
tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
|
||||
break;
|
||||
case AD_ACID:
|
||||
if (magr->mcan) {
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
if (resists_acid(mdef)) {
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s is covered in %s, but it seems harmless.",
|
||||
Monnam(mdef), hliquid("acid"));
|
||||
tmp = 0;
|
||||
} else if (g.vis && canseemon(mdef)) {
|
||||
pline("%s is covered in %s!", Monnam(mdef), hliquid("acid"));
|
||||
pline("It burns %s!", mon_nam(mdef));
|
||||
}
|
||||
if (!rn2(30))
|
||||
erode_armor(mdef, ERODE_CORRODE);
|
||||
if (!rn2(6))
|
||||
acid_damage(MON_WEP(mdef));
|
||||
break;
|
||||
case AD_RUST:
|
||||
if (magr->mcan)
|
||||
break;
|
||||
if (completelyrusts(pd)) { /* PM_IRON_GOLEM */
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s %s to pieces!", Monnam(mdef),
|
||||
!mlifesaver(mdef) ? "falls" : "starts to fall");
|
||||
monkilled(mdef, (char *) 0, AD_RUST);
|
||||
if (!DEADMONSTER(mdef))
|
||||
return 0;
|
||||
return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
}
|
||||
erode_armor(mdef, ERODE_RUST);
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_CORR:
|
||||
if (magr->mcan)
|
||||
break;
|
||||
erode_armor(mdef, ERODE_CORRODE);
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_DCAY:
|
||||
if (magr->mcan)
|
||||
break;
|
||||
if (completelyrots(pd)) { /* PM_WOOD_GOLEM || PM_LEATHER_GOLEM */
|
||||
/* note: the life-saved case is hypothetical because
|
||||
life-saving doesn't work for golems */
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s %s to pieces!", Monnam(mdef),
|
||||
!mlifesaver(mdef) ? "falls" : "starts to fall");
|
||||
monkilled(mdef, (char *) 0, AD_DCAY);
|
||||
if (!DEADMONSTER(mdef))
|
||||
return 0;
|
||||
return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
}
|
||||
erode_armor(mdef, ERODE_CORRODE);
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_STON:
|
||||
if (magr->mcan)
|
||||
break;
|
||||
do_stone:
|
||||
/* may die from the acid if it eats a stone-curing corpse */
|
||||
if (munstone(mdef, FALSE))
|
||||
goto post_stone;
|
||||
if (poly_when_stoned(pd)) {
|
||||
mon_to_stone(mdef);
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
if (!resists_ston(mdef)) {
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s turns to stone!", Monnam(mdef));
|
||||
monstone(mdef);
|
||||
post_stone:
|
||||
if (!DEADMONSTER(mdef))
|
||||
return 0;
|
||||
else if (mdef->mtame && !g.vis)
|
||||
You(brief_feeling, "peculiarly sad");
|
||||
return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
}
|
||||
tmp = (mattk->adtyp == AD_STON ? 0 : 1);
|
||||
break;
|
||||
case AD_TLPT:
|
||||
if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
|
||||
char mdef_Monnam[BUFSZ];
|
||||
boolean wasseen = canspotmon(mdef);
|
||||
|
||||
/* save the name before monster teleports, otherwise
|
||||
we'll get "it" in the suddenly disappears message */
|
||||
if (g.vis && wasseen)
|
||||
Strcpy(mdef_Monnam, Monnam(mdef));
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
(void) rloc(mdef, TRUE);
|
||||
if (g.vis && wasseen && !canspotmon(mdef) && mdef != u.usteed)
|
||||
pline("%s suddenly disappears!", mdef_Monnam);
|
||||
if (tmp >= mdef->mhp) { /* see hitmu(mhitu.c) */
|
||||
if (mdef->mhp == 1)
|
||||
++mdef->mhp;
|
||||
tmp = mdef->mhp - 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AD_SLEE:
|
||||
if (!cancelled && !mdef->msleeping
|
||||
&& sleep_monst(mdef, rnd(10), -1)) {
|
||||
if (g.vis && canspotmon(mdef)) {
|
||||
Strcpy(buf, Monnam(mdef));
|
||||
pline("%s is put to sleep by %s.", buf, mon_nam(magr));
|
||||
}
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
slept_monst(mdef);
|
||||
}
|
||||
break;
|
||||
case AD_PLYS:
|
||||
if (!cancelled && mdef->mcanmove) {
|
||||
if (g.vis && canspotmon(mdef)) {
|
||||
Strcpy(buf, Monnam(mdef));
|
||||
pline("%s is frozen by %s.", buf, mon_nam(magr));
|
||||
}
|
||||
paralyze_monst(mdef, rnd(10));
|
||||
}
|
||||
break;
|
||||
case AD_SLOW:
|
||||
if (!cancelled && mdef->mspeed != MSLOW) {
|
||||
unsigned int oldspeed = mdef->mspeed;
|
||||
|
||||
mon_adjust_speed(mdef, -1, (struct obj *) 0);
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
if (mdef->mspeed != oldspeed && g.vis && canspotmon(mdef))
|
||||
pline("%s slows down.", Monnam(mdef));
|
||||
}
|
||||
break;
|
||||
case AD_CONF:
|
||||
/* Since confusing another monster doesn't have a real time
|
||||
* limit, setting spec_used would not really be right (though
|
||||
* we still should check for it).
|
||||
*/
|
||||
if (!magr->mcan && !mdef->mconf && !magr->mspec_used) {
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s looks confused.", Monnam(mdef));
|
||||
mdef->mconf = 1;
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
}
|
||||
break;
|
||||
case AD_BLND:
|
||||
if (can_blnd(magr, mdef, mattk->aatyp, (struct obj *) 0)) {
|
||||
register unsigned rnd_tmp;
|
||||
|
||||
if (g.vis && mdef->mcansee && canspotmon(mdef))
|
||||
pline("%s is blinded.", Monnam(mdef));
|
||||
rnd_tmp = d((int) mattk->damn, (int) mattk->damd);
|
||||
if ((rnd_tmp += mdef->mblinded) > 127)
|
||||
rnd_tmp = 127;
|
||||
mdef->mblinded = rnd_tmp;
|
||||
mdef->mcansee = 0;
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
}
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_HALU:
|
||||
if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
|
||||
if (g.vis && canseemon(mdef))
|
||||
pline("%s looks %sconfused.", Monnam(mdef),
|
||||
mdef->mconf ? "more " : "");
|
||||
mdef->mconf = 1;
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
}
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_CURS:
|
||||
if (!night() && (pa == &mons[PM_GREMLIN]))
|
||||
break;
|
||||
if (!magr->mcan && !rn2(10)) {
|
||||
mdef->mcan = 1; /* cancelled regardless of lifesave */
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
if (is_were(pd) && pd->mlet != S_HUMAN)
|
||||
were_change(mdef);
|
||||
if (pd == &mons[PM_CLAY_GOLEM]) {
|
||||
if (g.vis && canseemon(mdef)) {
|
||||
pline("Some writing vanishes from %s head!",
|
||||
s_suffix(mon_nam(mdef)));
|
||||
pline("%s is destroyed!", Monnam(mdef));
|
||||
}
|
||||
mondied(mdef);
|
||||
if (!DEADMONSTER(mdef))
|
||||
return 0;
|
||||
else if (mdef->mtame && !g.vis)
|
||||
You(brief_feeling, "strangely sad");
|
||||
return (MM_DEF_DIED
|
||||
| (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
}
|
||||
if (!Deaf) {
|
||||
if (!g.vis)
|
||||
You_hear("laughter.");
|
||||
else if (canseemon(magr))
|
||||
pline("%s chuckles.", Monnam(magr));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AD_SGLD:
|
||||
tmp = 0;
|
||||
if (magr->mcan)
|
||||
break;
|
||||
/* technically incorrect; no check for stealing gold from
|
||||
* between mdef's feet...
|
||||
*/
|
||||
{
|
||||
struct obj *gold = findgold(mdef->minvent);
|
||||
|
||||
if (!gold)
|
||||
break;
|
||||
obj_extract_self(gold);
|
||||
add_to_minv(magr, gold);
|
||||
}
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
if (g.vis && canseemon(mdef)) {
|
||||
Strcpy(buf, Monnam(magr));
|
||||
pline("%s steals some gold from %s.", buf, mon_nam(mdef));
|
||||
}
|
||||
if (!tele_restrict(magr)) {
|
||||
boolean couldspot = canspotmon(magr);
|
||||
|
||||
(void) rloc(magr, TRUE);
|
||||
if (g.vis && couldspot && !canspotmon(magr))
|
||||
pline("%s suddenly disappears!", buf);
|
||||
}
|
||||
break;
|
||||
case AD_DRLI: /* drain life */
|
||||
if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
|
||||
tmp = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */
|
||||
if (g.vis && canspotmon(mdef))
|
||||
pline("%s becomes weaker!", Monnam(mdef));
|
||||
if (mdef->mhpmax - tmp > (int) mdef->m_lev) {
|
||||
mdef->mhpmax -= tmp;
|
||||
} else {
|
||||
/* limit floor of mhpmax reduction to current m_lev + 1;
|
||||
avoid increasing it if somehow already less than that */
|
||||
if (mdef->mhpmax > (int) mdef->m_lev)
|
||||
mdef->mhpmax = (int) mdef->m_lev + 1;
|
||||
}
|
||||
if (mdef->m_lev == 0) /* automatic kill if drained past level 0 */
|
||||
tmp = mdef->mhp;
|
||||
else
|
||||
mdef->m_lev--;
|
||||
|
||||
/* unlike hitting with Stormbringer, wounded attacker doesn't
|
||||
heal any from the drained life */
|
||||
}
|
||||
break;
|
||||
case AD_SSEX:
|
||||
case AD_SITM: /* for now these are the same */
|
||||
case AD_SEDU:
|
||||
if (magr->mcan)
|
||||
break;
|
||||
/* find an object to steal, non-cursed if magr is tame */
|
||||
for (obj = mdef->minvent; obj; obj = obj->nobj)
|
||||
if (!magr->mtame || !obj->cursed)
|
||||
break;
|
||||
|
||||
if (obj) {
|
||||
char onambuf[BUFSZ], mdefnambuf[BUFSZ];
|
||||
|
||||
/* make a special x_monnam() call that never omits
|
||||
the saddle, and save it for later messages */
|
||||
Strcpy(mdefnambuf,
|
||||
x_monnam(mdef, ARTICLE_THE, (char *) 0, 0, FALSE));
|
||||
|
||||
if (u.usteed == mdef && obj == which_armor(mdef, W_SADDLE))
|
||||
/* "You can no longer ride <steed>." */
|
||||
dismount_steed(DISMOUNT_POLY);
|
||||
obj_extract_self(obj);
|
||||
if (obj->owornmask) {
|
||||
mdef->misc_worn_check &= ~obj->owornmask;
|
||||
if (obj->owornmask & W_WEP)
|
||||
mwepgone(mdef);
|
||||
obj->owornmask = 0L;
|
||||
update_mon_intrinsics(mdef, obj, FALSE, FALSE);
|
||||
/* give monster a chance to wear other equipment on its next
|
||||
move instead of waiting until it picks something up */
|
||||
mdef->misc_worn_check |= I_SPECIAL;
|
||||
}
|
||||
/* add_to_minv() might free 'obj' [if it merges] */
|
||||
if (g.vis)
|
||||
Strcpy(onambuf, doname(obj));
|
||||
(void) add_to_minv(magr, obj);
|
||||
if (g.vis && canseemon(mdef)) {
|
||||
Strcpy(buf, Monnam(magr));
|
||||
pline("%s steals %s from %s!", buf, onambuf, mdefnambuf);
|
||||
}
|
||||
possibly_unwield(mdef, FALSE);
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
mselftouch(mdef, (const char *) 0, FALSE);
|
||||
if (DEADMONSTER(mdef))
|
||||
return (MM_DEF_DIED
|
||||
| (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
if (pa->mlet == S_NYMPH && !tele_restrict(magr)) {
|
||||
boolean couldspot = canspotmon(magr);
|
||||
|
||||
(void) rloc(magr, TRUE);
|
||||
if (g.vis && couldspot && !canspotmon(magr))
|
||||
pline("%s suddenly disappears!", buf);
|
||||
}
|
||||
}
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_DREN:
|
||||
if (!cancelled && !rn2(4))
|
||||
xdrainenergym(mdef, (boolean) (g.vis && canspotmon(mdef)
|
||||
&& mattk->aatyp != AT_ENGL));
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_DRST:
|
||||
case AD_DRDX:
|
||||
case AD_DRCO:
|
||||
if (!cancelled && !rn2(8)) {
|
||||
if (g.vis && canspotmon(magr))
|
||||
pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
|
||||
mpoisons_subj(magr, mattk));
|
||||
if (resists_poison(mdef)) {
|
||||
if (g.vis && canspotmon(mdef) && canspotmon(magr))
|
||||
pline_The("poison doesn't seem to affect %s.",
|
||||
mon_nam(mdef));
|
||||
} else {
|
||||
if (rn2(10))
|
||||
tmp += rn1(10, 6);
|
||||
else {
|
||||
if (g.vis && canspotmon(mdef))
|
||||
pline_The("poison was deadly...");
|
||||
tmp = mdef->mhp;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AD_DRIN:
|
||||
if (g.notonhead || !has_head(pd)) {
|
||||
if (g.vis && canspotmon(mdef))
|
||||
pline("%s doesn't seem harmed.", Monnam(mdef));
|
||||
/* Not clear what to do for green slimes */
|
||||
tmp = 0;
|
||||
/* don't bother with additional DRIN attacks since they wouldn't
|
||||
be able to hit target on head either */
|
||||
g.skipdrin = TRUE; /* affects mattackm()'s attack loop */
|
||||
break;
|
||||
}
|
||||
if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
|
||||
if (g.vis && canspotmon(magr) && canseemon(mdef)) {
|
||||
Strcpy(buf, s_suffix(Monnam(mdef)));
|
||||
pline("%s helmet blocks %s attack to %s head.", buf,
|
||||
s_suffix(mon_nam(magr)), mhis(mdef));
|
||||
}
|
||||
break;
|
||||
}
|
||||
res = eat_brains(magr, mdef, g.vis, &tmp);
|
||||
break;
|
||||
case AD_SLIM:
|
||||
if (cancelled)
|
||||
break; /* physical damage only */
|
||||
if (!rn2(4) && !slimeproof(pd)) {
|
||||
if (!munslime(mdef, FALSE) && !DEADMONSTER(mdef)) {
|
||||
if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE,
|
||||
(boolean) (g.vis && canseemon(mdef))))
|
||||
pd = mdef->data;
|
||||
mdef->mstrategy &= ~STRAT_WAITFORU;
|
||||
res = MM_HIT;
|
||||
}
|
||||
/* munslime attempt could have been fatal,
|
||||
potentially to multiple monsters (SCR_FIRE) */
|
||||
if (DEADMONSTER(magr))
|
||||
res |= MM_AGR_DIED;
|
||||
if (DEADMONSTER(mdef))
|
||||
res |= MM_DEF_DIED;
|
||||
tmp = 0;
|
||||
}
|
||||
break;
|
||||
case AD_STCK:
|
||||
if (cancelled)
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_WRAP: /* monsters cannot grab one another, it's too hard */
|
||||
if (magr->mcan)
|
||||
tmp = 0;
|
||||
break;
|
||||
case AD_ENCH:
|
||||
/* there's no msomearmor() function, so just do damage */
|
||||
/* if (cancelled) break; */
|
||||
break;
|
||||
case AD_POLY:
|
||||
if (!magr->mcan && tmp < mdef->mhp)
|
||||
tmp = mon_poly(magr, mdef, tmp);
|
||||
break;
|
||||
default:
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
if (!tmp)
|
||||
return res;
|
||||
|
||||
if ((mdef->mhp -= tmp) < 1) {
|
||||
if ((mdef->mhp -= mhm.damage) < 1) {
|
||||
if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */
|
||||
remove_monster(mdef->mx, mdef->my);
|
||||
mdef->mhp = 1; /* otherwise place_monster will complain */
|
||||
@@ -1495,8 +920,8 @@ int dieroll;
|
||||
monkilled(mdef, "", (int) mattk->adtyp);
|
||||
g.zombify = FALSE; /* reset */
|
||||
if (!DEADMONSTER(mdef))
|
||||
return res; /* mdef lifesaved */
|
||||
else if (res == MM_AGR_DIED)
|
||||
return mhm.hitflags; /* mdef lifesaved */
|
||||
else if (mhm.hitflags == MM_AGR_DIED)
|
||||
return (MM_DEF_DIED | MM_AGR_DIED);
|
||||
|
||||
if (mattk->adtyp == AD_DGST) {
|
||||
@@ -1518,7 +943,7 @@ int dieroll;
|
||||
|
||||
return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
|
||||
}
|
||||
return (res == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT;
|
||||
return (mhm.hitflags == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1682,9 +1107,9 @@ struct obj *otemp;
|
||||
* handled above. Returns same values as mattackm.
|
||||
*/
|
||||
static int
|
||||
passivemm(magr, mdef, mhit, mdead, mwep)
|
||||
passivemm(magr, mdef, mhitb, mdead, mwep)
|
||||
register struct monst *magr, *mdef;
|
||||
boolean mhit;
|
||||
boolean mhitb;
|
||||
int mdead;
|
||||
struct obj *mwep;
|
||||
{
|
||||
@@ -1692,6 +1117,7 @@ struct obj *mwep;
|
||||
register struct permonst *madat = magr->data;
|
||||
char buf[BUFSZ];
|
||||
int i, tmp;
|
||||
int mhit = mhitb ? MM_HIT : MM_MISS;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
if (i >= NATTK)
|
||||
@@ -1709,7 +1135,7 @@ struct obj *mwep;
|
||||
/* These affect the enemy even if defender killed */
|
||||
switch (mddat->mattk[i].adtyp) {
|
||||
case AD_ACID:
|
||||
if (mhit && !rn2(2)) {
|
||||
if (mhitb && !rn2(2)) {
|
||||
Strcpy(buf, Monnam(magr));
|
||||
if (canseemon(magr))
|
||||
pline("%s is splashed by %s %s!", buf,
|
||||
@@ -1727,7 +1153,7 @@ struct obj *mwep;
|
||||
acid_damage(MON_WEP(magr));
|
||||
goto assess_dmg;
|
||||
case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
|
||||
if (mhit && !mdef->mcan && mwep) {
|
||||
if (mhitb && !mdef->mcan && mwep) {
|
||||
(void) drain_item(mwep, FALSE);
|
||||
/* No message */
|
||||
}
|
||||
|
||||
850
src/mhitu.c
850
src/mhitu.c
File diff suppressed because it is too large
Load Diff
@@ -1586,17 +1586,11 @@ struct monst *mtmp;
|
||||
/* unicorn may not be able to avoid hero on a noteleport level */
|
||||
if (is_unicorn(mtmp->data) && !noteleport_level(mtmp))
|
||||
allowflags |= NOTONL;
|
||||
if (passes_walls(mtmp->data))
|
||||
allowflags |= (ALLOW_WALL | ALLOW_ROCK);
|
||||
if (passes_bars(mtmp->data))
|
||||
allowflags |= ALLOW_BARS;
|
||||
if (is_human(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR])
|
||||
allowflags |= ALLOW_SSM;
|
||||
if ((is_undead(mtmp->data) && mtmp->data->mlet != S_GHOST)
|
||||
|| is_vampshifter(mtmp))
|
||||
allowflags |= NOGARLIC;
|
||||
if (throws_rocks(mtmp->data))
|
||||
allowflags |= ALLOW_ROCK;
|
||||
|
||||
return allowflags;
|
||||
}
|
||||
|
||||
@@ -704,13 +704,13 @@ struct monst *mtmp, *mtarg;
|
||||
mtmp->weapon_check = NEED_RANGED_WEAPON;
|
||||
/* mon_wield_item resets weapon_check as appropriate */
|
||||
if (mon_wield_item(mtmp) != 0)
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
}
|
||||
|
||||
/* Pick a weapon */
|
||||
otmp = select_rwep(mtmp);
|
||||
if (!otmp)
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
ispole = is_pole(otmp);
|
||||
|
||||
x = mtmp->mx;
|
||||
@@ -725,17 +725,17 @@ struct monst *mtmp, *mtarg;
|
||||
if (ammo_and_launcher(otmp, mwep)
|
||||
&& dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
|
||||
> PET_MISSILE_RANGE2)
|
||||
return 0; /* Out of range */
|
||||
return MM_MISS; /* Out of range */
|
||||
/* Set target monster */
|
||||
g.mtarget = mtarg;
|
||||
g.marcher = mtmp;
|
||||
monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
|
||||
g.marcher = g.mtarget = (struct monst *) 0;
|
||||
nomul(0);
|
||||
return 1;
|
||||
return MM_HIT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
}
|
||||
|
||||
/* monster spits substance at monster */
|
||||
@@ -750,7 +750,7 @@ struct attack *mattk;
|
||||
if (!Deaf)
|
||||
pline("A dry rattle comes from %s throat.",
|
||||
s_suffix(mon_nam(mtmp)));
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
}
|
||||
if (m_lined_up(mtarg, mtmp)) {
|
||||
switch (mattk->adtyp) {
|
||||
@@ -759,7 +759,7 @@ struct attack *mattk;
|
||||
otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
|
||||
break;
|
||||
default:
|
||||
impossible("bad attack type in spitmu");
|
||||
impossible("bad attack type in spitmm");
|
||||
/*FALLTHRU*/
|
||||
case AD_ACID:
|
||||
otmp = mksobj(ACID_VENOM, TRUE, FALSE);
|
||||
@@ -784,10 +784,10 @@ struct attack *mattk;
|
||||
dog->hungrytime -= 5;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return MM_HIT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
}
|
||||
|
||||
/* monster breathes at monster (ranged) */
|
||||
@@ -807,7 +807,7 @@ struct attack *mattk;
|
||||
else
|
||||
You_hear("a cough.");
|
||||
}
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
}
|
||||
if (!mtmp->mspec_used && rn2(3)) {
|
||||
if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
|
||||
@@ -836,9 +836,9 @@ struct attack *mattk;
|
||||
}
|
||||
} else impossible("Breath weapon %d used", typ-1);
|
||||
} else
|
||||
return 0;
|
||||
return MM_MISS;
|
||||
}
|
||||
return 1;
|
||||
return MM_HIT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
85
src/read.c
85
src/read.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 read.c $NHDT-Date: 1600468453 2020/09/18 22:34:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.202 $ */
|
||||
/* NetHack 3.7 read.c $NHDT-Date: 1607200174 2020/12/05 20:29:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.204 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2012. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -214,8 +214,10 @@ struct obj *obj;
|
||||
int
|
||||
doread()
|
||||
{
|
||||
static const char find_any_braille[] = "feel any Braille writing.";
|
||||
register struct obj *scroll;
|
||||
boolean confused, nodisappear;
|
||||
int otyp;
|
||||
|
||||
/*
|
||||
* Reading while blind is allowed in most cases, including the
|
||||
@@ -241,9 +243,10 @@ doread()
|
||||
scroll = getobj(readable, "read");
|
||||
if (!scroll)
|
||||
return 0;
|
||||
otyp = scroll->otyp;
|
||||
|
||||
/* outrumor has its own blindness check */
|
||||
if (scroll->otyp == FORTUNE_COOKIE) {
|
||||
if (otyp == FORTUNE_COOKIE) {
|
||||
if (flags.verbose)
|
||||
You("break up the cookie and throw away the pieces.");
|
||||
outrumor(bcsign(scroll), BY_COOKIE);
|
||||
@@ -251,16 +254,16 @@ doread()
|
||||
u.uconduct.literate++;
|
||||
useup(scroll);
|
||||
return 1;
|
||||
} else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) {
|
||||
} else if (otyp == T_SHIRT || otyp == ALCHEMY_SMOCK) {
|
||||
char buf[BUFSZ], *mesg;
|
||||
const char *endpunct;
|
||||
|
||||
if (Blind) {
|
||||
You_cant("feel any Braille writing.");
|
||||
You_cant(find_any_braille);
|
||||
return 0;
|
||||
}
|
||||
/* can't read shirt worn under suit (under cloak is ok though) */
|
||||
if (scroll->otyp == T_SHIRT && uarm && scroll == uarmu) {
|
||||
if (otyp == T_SHIRT && uarm && scroll == uarmu) {
|
||||
pline("%s shirt is obscured by %s%s.",
|
||||
scroll->unpaid ? "That" : "Your", shk_your(buf, uarm),
|
||||
suit_simple_name(uarm));
|
||||
@@ -268,8 +271,8 @@ doread()
|
||||
}
|
||||
u.uconduct.literate++;
|
||||
/* populate 'buf[]' */
|
||||
mesg = (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf)
|
||||
: apron_text(scroll, buf);
|
||||
mesg = (otyp == T_SHIRT) ? tshirt_text(scroll, buf)
|
||||
: apron_text(scroll, buf);
|
||||
endpunct = "";
|
||||
if (flags.verbose) {
|
||||
int ln = (int) strlen(mesg);
|
||||
@@ -281,7 +284,37 @@ doread()
|
||||
}
|
||||
pline("\"%s\"%s", mesg, endpunct);
|
||||
return 1;
|
||||
} else if (scroll->otyp == CREDIT_CARD) {
|
||||
} else if ((otyp == DUNCE_CAP || otyp == CORNUTHAUM)
|
||||
/* note: "DUNCE" isn't directly connected to tourists but
|
||||
if everyone could read it, they would always be able to
|
||||
trivially distinguish between the two types of conical hat;
|
||||
limiting this to tourists is better than rejecting it */
|
||||
&& Role_if(PM_TOURIST)) {
|
||||
/* another note: the misspelling, "wizzard", is correct;
|
||||
that's what is written on Rincewind's pointy hat from
|
||||
Pratchett's Discworld series, along with a lot of stars;
|
||||
rather than inked on or painted on, treat them as stitched
|
||||
or even separate pieces of fabric which have been attached
|
||||
(don't recall whether the books mention anything like that...) */
|
||||
const char *cap_text = (otyp == DUNCE_CAP) ? "DUNCE" : "WIZZARD";
|
||||
|
||||
if (scroll->o_id % 3) {
|
||||
/* no need to vary this when blind; "on this ___" is important
|
||||
because it suggests that there might be something on others */
|
||||
You_cant("find anything to read on this %s.",
|
||||
simpleonames(scroll));
|
||||
return 0;
|
||||
}
|
||||
pline("%s on the %s. It reads: %s.",
|
||||
!Blind ? "There is writing" : "You feel lettering",
|
||||
simpleonames(scroll), cap_text);
|
||||
u.uconduct.literate++;
|
||||
/* yet another note: despite the fact that player will recognize
|
||||
the object type, don't make it become a discovery for hero */
|
||||
if (!objects[otyp].oc_name_known && !objects[otyp].oc_uname)
|
||||
docall(scroll);
|
||||
return 1;
|
||||
} else if (otyp == CREDIT_CARD) {
|
||||
static const char *card_msgs[] = {
|
||||
"Leprechaun Gold Tru$t - Shamrock Card",
|
||||
"Magic Memory Vault Charge Card",
|
||||
@@ -320,12 +353,12 @@ doread()
|
||||
(flags.verbose || Blind) ? "." : "");
|
||||
u.uconduct.literate++;
|
||||
return 1;
|
||||
} else if (scroll->otyp == CAN_OF_GREASE) {
|
||||
} else if (otyp == CAN_OF_GREASE) {
|
||||
pline("This %s has no label.", singular(scroll, xname));
|
||||
return 0;
|
||||
} else if (scroll->otyp == MAGIC_MARKER) {
|
||||
} else if (otyp == MAGIC_MARKER) {
|
||||
if (Blind) {
|
||||
You_cant("feel any Braille writing.");
|
||||
You_cant(find_any_braille);
|
||||
return 0;
|
||||
}
|
||||
if (flags.verbose)
|
||||
@@ -349,11 +382,11 @@ doread()
|
||||
pline("\"Odin.\"");
|
||||
u.uconduct.literate++;
|
||||
return 1;
|
||||
} else if (scroll->otyp == CANDY_BAR) {
|
||||
} else if (otyp == CANDY_BAR) {
|
||||
const char *wrapper = candy_wrapper_text(scroll);
|
||||
|
||||
if (Blind) {
|
||||
You_cant("feel any Braille writing.");
|
||||
You_cant(find_any_braille);
|
||||
return 0;
|
||||
}
|
||||
if (!*wrapper) {
|
||||
@@ -367,10 +400,10 @@ doread()
|
||||
&& scroll->oclass != SPBOOK_CLASS) {
|
||||
pline(silly_thing_to, "read");
|
||||
return 0;
|
||||
} else if (Blind && (scroll->otyp != SPE_BOOK_OF_THE_DEAD)) {
|
||||
} else if (Blind && otyp != SPE_BOOK_OF_THE_DEAD) {
|
||||
const char *what = 0;
|
||||
|
||||
if (scroll->otyp == SPE_NOVEL)
|
||||
if (otyp == SPE_NOVEL)
|
||||
/* unseen novels are already distinguishable from unseen
|
||||
spellbooks so this isn't revealing any extra information */
|
||||
what = "words";
|
||||
@@ -386,7 +419,7 @@ doread()
|
||||
|
||||
confused = (Confusion != 0);
|
||||
#ifdef MAIL
|
||||
if (scroll->otyp == SCR_MAIL) {
|
||||
if (otyp == SCR_MAIL) {
|
||||
confused = FALSE; /* override */
|
||||
/* reading mail is a convenience for the player and takes
|
||||
place outside the game, so shouldn't affect gameplay;
|
||||
@@ -405,24 +438,22 @@ doread()
|
||||
#endif
|
||||
|
||||
/* Actions required to win the game aren't counted towards conduct */
|
||||
/* Novel conduct is handled in read_tribute so exclude it too*/
|
||||
if (scroll->otyp != SPE_BOOK_OF_THE_DEAD
|
||||
&& scroll->otyp != SPE_BLANK_PAPER && scroll->otyp != SCR_BLANK_PAPER
|
||||
&& scroll->otyp != SPE_NOVEL)
|
||||
/* Novel conduct is handled in read_tribute so exclude it too */
|
||||
if (otyp != SPE_BOOK_OF_THE_DEAD && otyp != SPE_NOVEL
|
||||
&& otyp != SPE_BLANK_PAPER && otyp != SCR_BLANK_PAPER)
|
||||
u.uconduct.literate++;
|
||||
|
||||
if (scroll->oclass == SPBOOK_CLASS) {
|
||||
return study_book(scroll);
|
||||
}
|
||||
scroll->in_use = TRUE; /* scroll, not spellbook, now being read */
|
||||
if (scroll->otyp != SCR_BLANK_PAPER) {
|
||||
if (otyp != SCR_BLANK_PAPER) {
|
||||
boolean silently = !can_chant(&g.youmonst);
|
||||
|
||||
/* a few scroll feedback messages describe something happening
|
||||
to the scroll itself, so avoid "it disappears" for those */
|
||||
nodisappear = (scroll->otyp == SCR_FIRE
|
||||
|| (scroll->otyp == SCR_REMOVE_CURSE
|
||||
&& scroll->cursed));
|
||||
nodisappear = (otyp == SCR_FIRE
|
||||
|| (otyp == SCR_REMOVE_CURSE && scroll->cursed));
|
||||
if (Blind)
|
||||
pline(nodisappear
|
||||
? "You %s the formula on the scroll."
|
||||
@@ -440,14 +471,14 @@ doread()
|
||||
}
|
||||
}
|
||||
if (!seffects(scroll)) {
|
||||
if (!objects[scroll->otyp].oc_name_known) {
|
||||
if (!objects[otyp].oc_name_known) {
|
||||
if (g.known)
|
||||
learnscroll(scroll);
|
||||
else if (!objects[scroll->otyp].oc_uname)
|
||||
else if (!objects[otyp].oc_uname)
|
||||
docall(scroll);
|
||||
}
|
||||
scroll->in_use = FALSE;
|
||||
if (scroll->otyp != SCR_BLANK_PAPER)
|
||||
if (otyp != SCR_BLANK_PAPER)
|
||||
useup(scroll);
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -923,11 +923,14 @@ NHFILE *nhfp;
|
||||
if (buflen == -1)
|
||||
break;
|
||||
|
||||
len += (int) sizeof (stairway);
|
||||
if (nhfp->structlevel) {
|
||||
len += (int) sizeof (stairway);
|
||||
mread(nhfp->fd, (genericptr_t) &stway, sizeof (stairway));
|
||||
}
|
||||
|
||||
if (stway.tolev.dnum == u.uz.dnum) {
|
||||
/* stairway dlevel is relative, make it absolute */
|
||||
stway.tolev.dlevel += u.uz.dlevel;
|
||||
}
|
||||
stairway_add(stway.sx, stway.sy, stway.up, stway.isladder,
|
||||
&(stway.tolev));
|
||||
}
|
||||
|
||||
206
src/save.c
206
src/save.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 save.c $NHDT-Date: 1596498207 2020/08/03 23:43:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.160 $ */
|
||||
/* NetHack 3.7 save.c $NHDT-Date: 1606949327 2020/12/02 22:48:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.164 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Michael Allison, 2009. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -21,15 +21,12 @@ int dotcnt, dotrow; /* also used in restore */
|
||||
#endif
|
||||
|
||||
static void FDECL(savelevchn, (NHFILE *));
|
||||
static void FDECL(savedamage, (NHFILE *));
|
||||
/* static void FDECL(saveobj, (NHFILE *,struct obj *)); */
|
||||
/* static void FDECL(savemon, (NHFILE *,struct monst *)); */
|
||||
/* static void FDECL(savelevl, (NHFILE *, BOOLEAN_P)); */
|
||||
static void FDECL(saveobj, (NHFILE *,struct obj *));
|
||||
static void FDECL(savemon, (NHFILE *,struct monst *));
|
||||
static void FDECL(savelevl, (NHFILE *,BOOLEAN_P));
|
||||
static void FDECL(savedamage, (NHFILE *));
|
||||
static void FDECL(save_stairs, (NHFILE *));
|
||||
static void FDECL(saveobjchn, (NHFILE *,struct obj *));
|
||||
static void FDECL(saveobj, (NHFILE *,struct obj *));
|
||||
static void FDECL(saveobjchn, (NHFILE *,struct obj **));
|
||||
static void FDECL(savemon, (NHFILE *,struct monst *));
|
||||
static void FDECL(savemonchn, (NHFILE *,struct monst *));
|
||||
static void FDECL(savetrapchn, (NHFILE *,struct trap *));
|
||||
static void FDECL(savegamestate, (NHFILE *));
|
||||
@@ -86,7 +83,9 @@ dosave0()
|
||||
d_level uz_save;
|
||||
char whynot[BUFSZ];
|
||||
NHFILE *nhfp, *onhfp;
|
||||
int res = 0;
|
||||
|
||||
g.program_state.saving++; /* inhibit status and perm_invent updates */
|
||||
/* we may get here via hangup signal, in which case we want to fix up
|
||||
a few of things before saving so that they won't be restored in
|
||||
an improper state; these will be no-ops for normal save sequence */
|
||||
@@ -99,9 +98,9 @@ dosave0()
|
||||
u.uburied = 1, iflags.save_uburied = 0;
|
||||
|
||||
if (!g.program_state.something_worth_saving || !g.SAVEF[0])
|
||||
return 0;
|
||||
fq_save = fqname(g.SAVEF, SAVEPREFIX, 1); /* level files take 0 */
|
||||
goto done;
|
||||
|
||||
fq_save = fqname(g.SAVEF, SAVEPREFIX, 1); /* level files take 0 */
|
||||
#ifndef NO_SIGNAL
|
||||
#if defined(UNIX) || defined(VMS)
|
||||
sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
|
||||
@@ -118,7 +117,7 @@ dosave0()
|
||||
There("seems to be an old save file.");
|
||||
if (yn("Overwrite the old file?") == 'n') {
|
||||
nh_compress(fq_save);
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +128,7 @@ dosave0()
|
||||
if (!nhfp) {
|
||||
HUP pline("Cannot open save file.");
|
||||
(void) delete_savefile(); /* ab@unido */
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
vision_recalc(2); /* shut down vision to prevent problems
|
||||
@@ -158,6 +157,15 @@ dosave0()
|
||||
store_plname_in_file(nhfp);
|
||||
g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
|
||||
g.usteed_id = (u.usteed ? u.usteed->m_id : 0);
|
||||
/* savelev() might save uball and uchain, releasing their memory if
|
||||
FREEING, so we need to check their status now; if hero is swallowed,
|
||||
uball and uchain will persist beyond saving map floor and inventory
|
||||
so these copies of their pointers will be valid and savegamestate()
|
||||
will know to save them separately (from floor and invent); when not
|
||||
swallowed, uchain will be stale by then, and uball will be too if
|
||||
ball is on the floor rather than carried */
|
||||
g.looseball = BALL_IN_MON ? uball : 0;
|
||||
g.loosechain = CHAIN_IN_MON ? uchain : 0;
|
||||
savelev(nhfp, ledger_no(&u.uz));
|
||||
savegamestate(nhfp);
|
||||
|
||||
@@ -197,13 +205,13 @@ dosave0()
|
||||
(void) delete_savefile();
|
||||
HUP Strcpy(g.killer.name, whynot);
|
||||
HUP done(TRICKED);
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
minit(); /* ZEROCOMP */
|
||||
getlev(onhfp, g.hackpid, ltmp);
|
||||
close_nhfile(onhfp);
|
||||
if (nhfp->structlevel)
|
||||
bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
|
||||
bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* lvl no. */
|
||||
savelev(nhfp, ltmp); /* actual level*/
|
||||
delete_levelfile(ltmp);
|
||||
}
|
||||
@@ -217,7 +225,11 @@ dosave0()
|
||||
nh_compress(fq_save);
|
||||
/* this should probably come sooner... */
|
||||
g.program_state.something_worth_saving = 0;
|
||||
return 1;
|
||||
res = 1;
|
||||
|
||||
done:
|
||||
g.program_state.saving--;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -225,8 +237,9 @@ savegamestate(nhfp)
|
||||
NHFILE *nhfp;
|
||||
{
|
||||
unsigned long uid;
|
||||
struct obj * bc_objs = (struct obj *)0;
|
||||
struct obj *bc_objs = (struct obj *)0;
|
||||
|
||||
g.program_state.saving++; /* caller should/did already set this... */
|
||||
uid = (unsigned long) getuid();
|
||||
if (nhfp->structlevel) {
|
||||
bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid);
|
||||
@@ -251,27 +264,31 @@ NHFILE *nhfp;
|
||||
save_timers(nhfp, RANGE_GLOBAL);
|
||||
save_light_sources(nhfp, RANGE_GLOBAL);
|
||||
|
||||
saveobjchn(nhfp, g.invent);
|
||||
/* when FREEING, deletes objects in invent and sets invent to Null;
|
||||
pointers into invent (uwep, uarmg, uamul, &c) are set to Null too */
|
||||
saveobjchn(nhfp, &g.invent);
|
||||
|
||||
/* save ball and chain if they are currently dangling free (i.e. not on
|
||||
floor or in inventory) */
|
||||
if (CHAIN_IN_MON) {
|
||||
uchain->nobj = bc_objs;
|
||||
bc_objs = uchain;
|
||||
/* save ball and chain if they are currently dangling free (i.e. not
|
||||
on floor or in inventory); 'looseball' and 'loosechain' have been
|
||||
set up in caller because ball and chain will be gone by now if on
|
||||
floor, or ball gone if carried; caveat: uball and uchain pointers
|
||||
will be non-Null but stale (point to freed memory) in those cases */
|
||||
bc_objs = (struct obj *) 0;
|
||||
if (g.loosechain) {
|
||||
g.loosechain->nobj = bc_objs; /* uchain */
|
||||
bc_objs = g.loosechain;
|
||||
}
|
||||
if (BALL_IN_MON) {
|
||||
uball->nobj = bc_objs;
|
||||
bc_objs = uball;
|
||||
if (g.looseball) {
|
||||
g.looseball->nobj = bc_objs;
|
||||
bc_objs = g.looseball;
|
||||
}
|
||||
saveobjchn(nhfp, bc_objs);
|
||||
saveobjchn(nhfp, &bc_objs); /* frees objs in list, sets bc_objs to Null */
|
||||
g.looseball = g.loosechain = (struct obj *) 0;
|
||||
|
||||
saveobjchn(nhfp, g.migrating_objs);
|
||||
saveobjchn(nhfp, &g.migrating_objs); /* frees objs and sets to Null */
|
||||
savemonchn(nhfp, g.migrating_mons);
|
||||
if (release_data(nhfp)) {
|
||||
g.invent = 0;
|
||||
g.migrating_objs = 0;
|
||||
g.migrating_mons = 0;
|
||||
}
|
||||
if (release_data(nhfp))
|
||||
g.migrating_mons = (struct monst *) 0;
|
||||
if (nhfp->structlevel)
|
||||
bwrite(nhfp->fd, (genericptr_t) g.mvitals, sizeof g.mvitals);
|
||||
save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp),
|
||||
@@ -304,8 +321,11 @@ NHFILE *nhfp;
|
||||
save_msghistory(nhfp);
|
||||
if (nhfp->structlevel)
|
||||
bflush(nhfp->fd);
|
||||
g.program_state.saving--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* potentially called from goto_level(do.c) as well as savestateinlock() */
|
||||
boolean
|
||||
tricked_fileremoved(nhfp, whynot)
|
||||
NHFILE *nhfp;
|
||||
@@ -329,6 +349,7 @@ savestateinlock()
|
||||
char whynot[BUFSZ];
|
||||
NHFILE *nhfp;
|
||||
|
||||
g.program_state.saving++; /* inhibit status and perm_invent updates */
|
||||
/* When checkpointing is on, the full state needs to be written
|
||||
* on each checkpoint. When checkpointing is off, only the pid
|
||||
* needs to be in the level.0 file, so it does not need to be
|
||||
@@ -348,24 +369,31 @@ savestateinlock()
|
||||
* readable by an external utility
|
||||
*/
|
||||
nhfp = open_levelfile(0, whynot);
|
||||
if (tricked_fileremoved(nhfp, whynot))
|
||||
if (tricked_fileremoved(nhfp, whynot)) {
|
||||
g.program_state.saving--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (nhfp->structlevel)
|
||||
(void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid);
|
||||
if (g.hackpid != hpid) {
|
||||
Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!",
|
||||
hpid, g.hackpid);
|
||||
pline1(whynot);
|
||||
Strcpy(g.killer.name, whynot);
|
||||
done(TRICKED);
|
||||
goto giveup;
|
||||
}
|
||||
close_nhfile(nhfp);
|
||||
|
||||
nhfp = create_levelfile(0, whynot);
|
||||
if (!nhfp) {
|
||||
pline1(whynot);
|
||||
giveup:
|
||||
Strcpy(g.killer.name, whynot);
|
||||
/* done(TRICKED) will return when running in wizard mode;
|
||||
clear the display-update-suppression flag before rather
|
||||
than after so that screen updating behaves normally;
|
||||
game data shouldn't be inconsistent yet, unlike it would
|
||||
become midway through saving */
|
||||
g.program_state.saving--;
|
||||
done(TRICKED);
|
||||
return;
|
||||
}
|
||||
@@ -384,11 +412,15 @@ savestateinlock()
|
||||
|
||||
g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
|
||||
g.usteed_id = (u.usteed ? u.usteed->m_id : 0);
|
||||
g.looseball = BALL_IN_MON ? uball : 0;
|
||||
g.loosechain = CHAIN_IN_MON ? uchain : 0;
|
||||
savegamestate(nhfp);
|
||||
}
|
||||
close_nhfile(nhfp);
|
||||
}
|
||||
g.program_state.saving--;
|
||||
g.havestate = flags.ins_chkpt;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -401,6 +433,7 @@ xchar lev;
|
||||
short tlev;
|
||||
#endif
|
||||
|
||||
g.program_state.saving++; /* even if current mode is FREEING */
|
||||
/*
|
||||
* Level file contents:
|
||||
* version info (handled by caller);
|
||||
@@ -454,7 +487,8 @@ xchar lev;
|
||||
if (nhfp->mode == FREEING) /* see above */
|
||||
goto skip_lots;
|
||||
|
||||
savelevl(nhfp, (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
|
||||
savelevl(nhfp,
|
||||
(boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
|
||||
if (nhfp->structlevel) {
|
||||
bwrite(nhfp->fd, (genericptr_t) g.lastseentyp, sizeof g.lastseentyp);
|
||||
bwrite(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
|
||||
@@ -475,9 +509,9 @@ xchar lev;
|
||||
savemonchn(nhfp, fmon);
|
||||
save_worm(nhfp); /* save worm information */
|
||||
savetrapchn(nhfp, g.ftrap);
|
||||
saveobjchn(nhfp, fobj);
|
||||
saveobjchn(nhfp, g.level.buriedobjlist);
|
||||
saveobjchn(nhfp, g.billobjs);
|
||||
saveobjchn(nhfp, &fobj);
|
||||
saveobjchn(nhfp, &g.level.buriedobjlist);
|
||||
saveobjchn(nhfp, &g.billobjs);
|
||||
if (release_data(nhfp)) {
|
||||
int x,y;
|
||||
/* TODO: maybe use clear_level_structures() */
|
||||
@@ -503,6 +537,8 @@ xchar lev;
|
||||
if (nhfp->structlevel)
|
||||
bflush(nhfp->fd);
|
||||
}
|
||||
g.program_state.saving--;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -564,6 +600,7 @@ boolean rlecomp;
|
||||
if (nhfp->structlevel) {
|
||||
bwrite(nhfp->fd, (genericptr_t) levl, sizeof levl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* used when saving a level and also when saving dungeon overview data */
|
||||
@@ -622,6 +659,40 @@ NHFILE *nhfp;
|
||||
g.level.damagelist = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
save_stairs(nhfp)
|
||||
NHFILE *nhfp;
|
||||
{
|
||||
stairway *stway = g.stairs;
|
||||
int buflen = (int) sizeof *stway;
|
||||
|
||||
while (stway) {
|
||||
if (perform_bwrite(nhfp)) {
|
||||
if (stway->tolev.dnum == u.uz.dnum) {
|
||||
/* make dlevel relative to current level */
|
||||
stway->tolev.dlevel -= u.uz.dlevel;
|
||||
}
|
||||
if (nhfp->structlevel) {
|
||||
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
|
||||
bwrite(nhfp->fd, (genericptr_t) stway, sizeof *stway);
|
||||
}
|
||||
if (stway->tolev.dnum == u.uz.dnum) {
|
||||
/* reset staiway dlevel back to absolute */
|
||||
stway->tolev.dlevel += u.uz.dlevel;
|
||||
}
|
||||
}
|
||||
stway = stway->next;
|
||||
}
|
||||
if (perform_bwrite(nhfp)) {
|
||||
buflen = -1;
|
||||
if (nhfp->structlevel) {
|
||||
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* save one object;
|
||||
caveat: this is only for perform_bwrite(); caller handles release_data() */
|
||||
static void
|
||||
saveobj(nhfp, otmp)
|
||||
NHFILE *nhfp;
|
||||
@@ -660,46 +731,22 @@ struct obj *otmp;
|
||||
}
|
||||
/* omid used to be indirect via a pointer in oextra but has
|
||||
become part of oextra itself; 0 means not applicable and
|
||||
gets saved/restored whenever any other oxtra components do */
|
||||
gets saved/restored whenever any other oextra components do */
|
||||
if (nhfp->structlevel)
|
||||
bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp));
|
||||
}
|
||||
}
|
||||
|
||||
/* save an object chain; sets head of list to Null when done;
|
||||
handles release_data() for each object in the list */
|
||||
static void
|
||||
save_stairs(nhfp)
|
||||
saveobjchn(nhfp, obj_p)
|
||||
NHFILE *nhfp;
|
||||
struct obj **obj_p;
|
||||
{
|
||||
stairway *stway = g.stairs;
|
||||
int buflen = (int) sizeof (stairway);
|
||||
int len = 0;
|
||||
|
||||
while (stway) {
|
||||
if (perform_bwrite(nhfp)) {
|
||||
if (nhfp->structlevel) {
|
||||
len += sizeof(buflen);
|
||||
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
|
||||
len += sizeof(stairway);
|
||||
bwrite(nhfp->fd, (genericptr_t) stway, sizeof(stairway));
|
||||
}
|
||||
}
|
||||
stway = stway->next;
|
||||
}
|
||||
if (perform_bwrite(nhfp)) {
|
||||
if (nhfp->structlevel) {
|
||||
buflen = -1;
|
||||
len += sizeof(buflen);
|
||||
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
saveobjchn(nhfp, otmp)
|
||||
NHFILE *nhfp;
|
||||
register struct obj *otmp;
|
||||
{
|
||||
register struct obj *otmp2;
|
||||
register struct obj *otmp = *obj_p;
|
||||
struct obj *otmp2;
|
||||
boolean is_invent = (otmp && otmp == g.invent);
|
||||
int minusone = -1;
|
||||
|
||||
while (otmp) {
|
||||
@@ -708,7 +755,7 @@ register struct obj *otmp;
|
||||
saveobj(nhfp, otmp);
|
||||
}
|
||||
if (Has_contents(otmp))
|
||||
saveobjchn(nhfp, otmp->cobj);
|
||||
saveobjchn(nhfp, &otmp->cobj);
|
||||
if (release_data(nhfp)) {
|
||||
/*
|
||||
* If these are on the floor, the discarding could be
|
||||
@@ -733,6 +780,10 @@ register struct obj *otmp;
|
||||
otmp->cobj = NULL; /* contents handled above */
|
||||
otmp->timed = 0; /* not timed any more */
|
||||
otmp->lamplit = 0; /* caller handled lights */
|
||||
otmp->leashmon = 0; /* mon->mleashed could still be set;
|
||||
* unfortunately, we can't clear that
|
||||
* until after the monster is saved */
|
||||
otmp->owornmask = 0L; /* no longer care */
|
||||
dealloc_obj(otmp);
|
||||
}
|
||||
otmp = otmp2;
|
||||
@@ -741,6 +792,11 @@ register struct obj *otmp;
|
||||
if (nhfp->structlevel)
|
||||
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int));
|
||||
}
|
||||
if (release_data(nhfp)) {
|
||||
if (is_invent)
|
||||
allunworn(); /* clear uwep, uarm, uball, &c pointers */
|
||||
*obj_p = (struct obj *) 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -825,7 +881,7 @@ register struct monst *mtmp;
|
||||
savemon(nhfp, mtmp);
|
||||
}
|
||||
if (mtmp->minvent)
|
||||
saveobjchn(nhfp, mtmp->minvent);
|
||||
saveobjchn(nhfp, &mtmp->minvent);
|
||||
if (release_data(nhfp)) {
|
||||
if (mtmp == g.context.polearm.hitmon) {
|
||||
g.context.polearm.m_id = mtmp->m_id;
|
||||
@@ -1033,7 +1089,7 @@ freedynamicdata()
|
||||
tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
|
||||
#ifdef FREE_ALL_MEMORY
|
||||
#define free_current_level() savelev(&tnhfp, -1)
|
||||
#define freeobjchn(X) (saveobjchn(&tnhfp, X), X = 0)
|
||||
#define freeobjchn(X) (saveobjchn(&tnhfp, &X), X = 0)
|
||||
#define freemonchn(X) (savemonchn(&tnhfp, X), X = 0)
|
||||
#define freefruitchn() savefruitchn(&tnhfp)
|
||||
#define freenames() savenames(&tnhfp)
|
||||
|
||||
2656
src/uhitm.c
2656
src/uhitm.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 wield.c $NHDT-Date: 1596498228 2020/08/03 23:43:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.77 $ */
|
||||
/* NetHack 3.7 wield.c $NHDT-Date: 1607200367 2020/12/05 20:32:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.78 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2009. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -275,7 +275,7 @@ static NEARDATA const char wield_objs[] = {
|
||||
static NEARDATA const char ready_objs[] = {
|
||||
ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0
|
||||
};
|
||||
static NEARDATA const char bullets[] = { /* (note: different from dothrow.c) */
|
||||
static NEARDATA const char w_bullets[] = { /* (different from dothrow.c) */
|
||||
ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE,
|
||||
GEM_CLASS, WEAPON_CLASS, 0
|
||||
};
|
||||
@@ -455,7 +455,7 @@ dowieldquiver()
|
||||
quivee_types = (uslinging()
|
||||
|| (uswapwep
|
||||
&& objects[uswapwep->otyp].oc_skill == P_SLING))
|
||||
? bullets
|
||||
? w_bullets
|
||||
: ready_objs;
|
||||
newquiver = getobj(quivee_types, "ready");
|
||||
|
||||
|
||||
22
src/worn.c
22
src/worn.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 worn.c $NHDT-Date: 1596498231 2020/08/03 23:43:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.67 $ */
|
||||
/* NetHack 3.7 worn.c $NHDT-Date: 1606919259 2020/12/02 14:27:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.70 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2013. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -131,7 +131,7 @@ register struct obj *obj;
|
||||
is pending (via 'A' command for multiple items) */
|
||||
cancel_doff(obj, wp->w_mask);
|
||||
|
||||
*(wp->w_obj) = 0;
|
||||
*(wp->w_obj) = (struct obj *) 0;
|
||||
p = objects[obj->otyp].oc_oprop;
|
||||
u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
|
||||
obj->owornmask &= ~wp->w_mask;
|
||||
@@ -145,6 +145,24 @@ register struct obj *obj;
|
||||
update_inventory();
|
||||
}
|
||||
|
||||
/* called when saving with FREEING flag set has just discarded inventory */
|
||||
void
|
||||
allunworn()
|
||||
{
|
||||
const struct worn *wp;
|
||||
|
||||
u.twoweap = 0; /* uwep and uswapwep are going away */
|
||||
/* remove stale pointers; called after the objects have been freed
|
||||
(without first being unworn) while saving invent during game save;
|
||||
note: uball and uchain might not be freed yet but we clear them
|
||||
here anyway (savegamestate() and its callers deal with them) */
|
||||
for (wp = worn; wp->w_mask; wp++) {
|
||||
/* object is already gone so we don't/can't update is owornmask */
|
||||
*(wp->w_obj) = (struct obj *) 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* return item worn in slot indiciated by wornmask; needed by poly_obj() */
|
||||
struct obj *
|
||||
wearmask_to_obj(wornmask)
|
||||
|
||||
@@ -1192,6 +1192,32 @@ $(O)envchk.tag: $(O)obj.tag
|
||||
#==========================================
|
||||
#=========== SECONDARY TARGETS ============
|
||||
#==========================================
|
||||
fetch-lua: fetch-actual-Lua
|
||||
|
||||
fetch-Lua: fetch-actual-Lua
|
||||
|
||||
fetch-actual-Lua:
|
||||
@if not exist ..\lib\*.* mkdir ..\lib
|
||||
cd ..\lib
|
||||
curl -R -O http://www.lua.org/ftp/lua-$(LUAVER).tar.gz
|
||||
tar zxf lua-$(LUAVER).tar.gz
|
||||
if exist lua-$(LUAVER).tar.gz del lua-$(LUAVER).tar.gz
|
||||
if exist lua-$(LUAVER).tar del lua-$(LUAVER).tar
|
||||
cd ..\src
|
||||
@echo Lua has been fetched into ..\lib\lua-$(LUAVER)
|
||||
|
||||
fetch-pdcurses:
|
||||
@if not exist ..\lib\*.* mkdir ..\lib
|
||||
cd ..\lib
|
||||
curl -L -R https://codeload.github.com/wmcbrine/PDCurses/zip/master -o pdcurses.zip
|
||||
powershell -command "Expand-Archive -Path .\pdcurses.zip -DestinationPath ./pdcurses-temp"
|
||||
if exist .\pdcurses\* rd .\pdcurses /s /Q
|
||||
move .\pdcurses-temp\PDCurses-master .
|
||||
ren PDCurses-master pdcurses
|
||||
if exist .\pdcurses-temp\* rd .\pdcurses-temp /s /Q
|
||||
if exist .\pdcurses.zip del .\pdcurses.zip
|
||||
cd ..\src
|
||||
@echo pdcurses has been fetched into ..\lib\pdcurses
|
||||
|
||||
#==========================================
|
||||
# DLB utility and nhdatNNN file creation
|
||||
|
||||
@@ -167,26 +167,40 @@ void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event)
|
||||
if (promptstr != "#")
|
||||
prompt->setText(promptstr.left(promptstr.size() - 1));
|
||||
enableButtons();
|
||||
/*} else if (uc == '\r' || uc == '\n'; || uc == ' ') {*/
|
||||
} else if (uc < ' ' || uc > std::max('z', 'Z')) {
|
||||
} else if ((uc < ' ' && !(uc == '\n' || uc == '\r'))
|
||||
|| uc > std::max('z', 'Z')) {
|
||||
reject(); // done()
|
||||
} else {
|
||||
promptstr += QChar(uc); // event()->text()
|
||||
// <return> is necessary if one command is a leading substring
|
||||
// of another and superfluous otherwise
|
||||
boolean checkexact = (uc == '\n' || uc == '\r' || uc == ' ');
|
||||
if (!checkexact)
|
||||
promptstr += QChar(uc); // event()->text()
|
||||
QString typedstr = promptstr.mid(1); // skip the '#'
|
||||
unsigned matches = 0;
|
||||
unsigned match = 0;
|
||||
unsigned matchindx = 0;
|
||||
for (unsigned i=0; extcmdlist[i].ef_txt; i++) {
|
||||
if (!interesting_command(i))
|
||||
continue;
|
||||
if (QString(extcmdlist[i].ef_txt).startsWith(typedstr)) {
|
||||
++matches;
|
||||
if (matches >= 2)
|
||||
break;
|
||||
match = i;
|
||||
QString cmdtxt = QString(extcmdlist[i].ef_txt);
|
||||
if (cmdtxt.startsWith(typedstr)) {
|
||||
if (checkexact) {
|
||||
if (cmdtxt == typedstr) {
|
||||
matchindx = i;
|
||||
matches = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (++matches >= 2)
|
||||
break;
|
||||
matchindx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matches == 1)
|
||||
done(match+1);
|
||||
done(matchindx + 1);
|
||||
else if (checkexact)
|
||||
reject();
|
||||
else if (matches >= 2)
|
||||
prompt->setText(promptstr);
|
||||
enableButtons();
|
||||
|
||||
Reference in New Issue
Block a user