Merge branch 'NetHack-3.7' of https://rodney.nethack.org:20040/git/NHsource into NetHack-3.7

This commit is contained in:
Bart House
2020-12-05 17:32:17 -08:00
22 changed files with 2865 additions and 1832 deletions
+13 -2
View File
@@ -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 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 autodescribe when moving the cursor was erroneously honoring MSGTYPE=stop
and potentially delivering sounds and potentially delivering sounds
reduce the number of "seeXYZ" commands by renaming some: #seenv -> #wizseenv, 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 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 field is empty in the character selection widget
Qt: when a new message is issued, pan the message window to its left edge if 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 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' 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 for instance), clicking on [Search], entering a search target in the
resulting popup and clicking on [Okay] or typing <return>, the text 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 reading blessed scroll of teleportation confers one-shot teleport control
mild zombie apocalypse mild zombie apocalypse
list lamps and lanterns in charging prompt list lamps and lanterns in charging prompt
let tourists read conical hats
Platform- and/or Interface-Specific New Features 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'; move 'restoring' to the program_state struct; add corresponding 'saving';
both used to enforce no updating of status lines or of persistent both used to enforce no updating of status lines or of persistent
inventory when the relevant activity is in progress 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
+3 -1
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2007. */ /*-Copyright (c) Michael Allison, 2007. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1103,6 +1103,8 @@ struct instance_globals {
boolean havestate; boolean havestate;
unsigned ustuck_id; /* need to preserve during save */ unsigned ustuck_id; /* need to preserve during save */
unsigned usteed_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 */ /* shk.c */
/* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */ /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */
+48 -2
View File
@@ -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. */ /* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1282,6 +1282,7 @@ E void FDECL(rustm, (struct monst *, struct obj *));
/* ### mhitu.c ### */ /* ### mhitu.c ### */
E void FDECL(hitmsg, (struct monst *, struct attack *));
E const char *FDECL(mpoisons_subj, (struct monst *, struct attack *)); E const char *FDECL(mpoisons_subj, (struct monst *, struct attack *));
E void NDECL(u_slow_down); E void NDECL(u_slow_down);
E struct monst *NDECL(cloneu); 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 *, E struct attack *FDECL(getmattk, (struct monst *, struct monst *,
int, int *, struct attack *)); int, int *, struct attack *));
E int FDECL(mattacku, (struct monst *)); 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 int FDECL(magic_negation, (struct monst *));
E boolean NDECL(gulp_blnd_check); E boolean NDECL(gulp_blnd_check);
E int FDECL(gazemu, (struct monst *, struct attack *)); 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(hmon, (struct monst *, struct obj *, int, int));
E boolean FDECL(shade_miss, (struct monst *, struct monst *, struct obj *, E boolean FDECL(shade_miss, (struct monst *, struct monst *, struct obj *,
BOOLEAN_P, BOOLEAN_P)); 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 int FDECL(damageum, (struct monst *, struct attack *, int));
E void FDECL(missum, (struct monst *, struct attack *, BOOLEAN_P)); 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)); UCHAR_P, BOOLEAN_P));
E void FDECL(passive_obj, (struct monst *, struct obj *, struct attack *)); E void FDECL(passive_obj, (struct monst *, struct obj *, struct attack *));
E void FDECL(stumble_onto_mimic, (struct monst *)); 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(setworn, (struct obj *, long));
E void FDECL(setnotworn, (struct obj *)); E void FDECL(setnotworn, (struct obj *));
E void NDECL(allunworn);
E struct obj *FDECL(wearmask_to_obj, (long)); E struct obj *FDECL(wearmask_to_obj, (long));
E long FDECL(wearslot, (struct obj *)); E long FDECL(wearslot, (struct obj *));
E void FDECL(mon_set_minvis, (struct monst *)); E void FDECL(mon_set_minvis, (struct monst *));
+10
View File
@@ -86,6 +86,15 @@
#define AD_SAMU 252 /* hits, may steal Amulet (Wizard) */ #define AD_SAMU 252 /* hits, may steal Amulet (Wizard) */
#define AD_CURS 253 /* random curse (ex. gremlin) */ #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), * Monster to monster attacks. When a monster attacks another (mattackm),
* any or all of the following can be returned. See mattackm() for more * 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_HIT 0x1 /* aggressor hit defender */
#define MM_DEF_DIED 0x2 /* defender died */ #define MM_DEF_DIED 0x2 /* defender died */
#define MM_AGR_DIED 0x4 /* aggressor died */ #define MM_AGR_DIED 0x4 /* aggressor died */
#define MM_AGR_DONE 0x8 /* aggressor is done with their turn */
#endif /* MONATTK_H */ #endif /* MONATTK_H */
+1 -1
View File
@@ -17,7 +17,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones * Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files. * and save files.
*/ */
#define EDITLEVEL 27 #define EDITLEVEL 28
/* /*
* Development status possibilities. * Development status possibilities.
+10 -6
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1873,26 +1873,29 @@ struct ext_func_tab extcmdlist[] = {
dopramulet, IFBURIED }, dopramulet, IFBURIED },
{ ARMOR_SYM, "seearmor", "show the armor currently worn", { ARMOR_SYM, "seearmor", "show the armor currently worn",
doprarm, IFBURIED }, doprarm, IFBURIED },
{ GOLD_SYM, "seegold", "count your gold", doprgold, IFBURIED },
{ RING_SYM, "seerings", "show the ring(s) currently worn", { RING_SYM, "seerings", "show the ring(s) currently worn",
doprring, IFBURIED }, doprring, IFBURIED },
{ TOOL_SYM, "seetools", "show the tools currently in use", { TOOL_SYM, "seetools", "show the tools currently in use",
doprtool, IFBURIED }, doprtool, IFBURIED },
{ WEAPON_SYM, "seeweapon", "show the weapon currently wielded", { WEAPON_SYM, "seeweapon", "show the weapon currently wielded",
doprwep, IFBURIED }, doprwep, IFBURIED },
{ '!', "shell", "do a shell escape", { '!', "shell", "leave game to enter a sub-shell ('exit' to come back)",
dosh_core, IFBURIED | GENERALCMD dosh_core, IFBURIED | GENERALCMD
#ifndef SHELL #ifndef SHELL
| CMD_NOT_AVAILABLE | CMD_NOT_AVAILABLE
#endif /* SHELL */ #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", { SPBOOK_SYM, "showspells", "list and reorder known spells",
dovspell, IFBURIED }, 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 }, { M('s'), "sit", "sit down", dosit, AUTOCOMPLETE },
{ '\0', "stats", "show memory statistics", { '\0', "stats", "show memory statistics",
wiz_show_stats, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, 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 dosuspend_core, IFBURIED | GENERALCMD
#ifndef SUSPEND #ifndef SUSPEND
| CMD_NOT_AVAILABLE | CMD_NOT_AVAILABLE
@@ -1922,7 +1925,8 @@ struct ext_func_tab extcmdlist[] = {
{ M('v'), "version", { M('v'), "version",
"list compile time options for this version of NetHack", "list compile time options for this version of NetHack",
doextversion, IFBURIED | AUTOCOMPLETE | GENERALCMD }, 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", { '\0', "vision", "show vision array",
wiz_show_vision, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, wiz_show_vision, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
{ '.', "wait", "rest one move while doing nothing", { '.', "wait", "rest one move while doing nothing",
+3 -1
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2009. */ /*-Copyright (c) Michael Allison, 2009. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -611,6 +611,8 @@ const struct instance_globals g_init = {
TRUE, /* havestate*/ TRUE, /* havestate*/
0, /* ustuck_id */ 0, /* ustuck_id */
0, /* usteed_id */ 0, /* usteed_id */
(struct obj *) 0, /* looseball */
(struct obj *) 0, /* loosechain */
/* shk.c */ /* shk.c */
'a', /* sell_response */ 'a', /* sell_response */
+5 -1
View File
@@ -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 */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
/* and Dave Cohrs, 1990. */ /* and Dave Cohrs, 1990. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1691,6 +1691,10 @@ int cursor_on_u;
static int delay_flushing = 0; static int delay_flushing = 0;
register int x, y; 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) if (cursor_on_u == -1)
delay_flushing = !delay_flushing; delay_flushing = !delay_flushing;
if (delay_flushing) if (delay_flushing)
+18 -11
View File
@@ -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(kick_object, (XCHAR_P, XCHAR_P, char *));
static int FDECL(really_kick_object, (XCHAR_P, XCHAR_P)); static int FDECL(really_kick_object, (XCHAR_P, XCHAR_P));
static char *FDECL(kickstr, (char *, const char *)); 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 void FDECL(drop_to, (coord *, SCHAR_P, XCHAR_P, XCHAR_P));
static const char kick_passes_thru[] = "kick passes harmlessly through"; static const char kick_passes_thru[] = "kick passes harmlessly through";
@@ -1510,7 +1510,7 @@ boolean shop_floor_obj;
coord cc; coord cc;
struct obj *obj; struct obj *obj;
struct trap *t; struct trap *t;
boolean nodrop, unpaid, container, impact = FALSE; boolean nodrop, unpaid, container, impact = FALSE, chainthere = FALSE;
long n = 0L; long n = 0L;
if (!otmp) if (!otmp)
@@ -1530,9 +1530,12 @@ boolean shop_floor_obj;
unpaid = is_unpaid(otmp); unpaid = is_unpaid(otmp);
if (OBJ_AT(x, y)) { if (OBJ_AT(x, y)) {
for (obj = g.level.objects[x][y]; obj; obj = obj->nexthere) for (obj = g.level.objects[x][y]; obj; obj = obj->nexthere) {
if (obj != otmp) if (obj == uchain)
chainthere = TRUE;
else if (obj != otmp)
n += obj->quan; n += obj->quan;
}
if (n) if (n)
impact = TRUE; impact = TRUE;
} }
@@ -1546,7 +1549,7 @@ boolean shop_floor_obj;
} }
if (cansee(x, y)) if (cansee(x, y))
otransit_msg(otmp, nodrop, n); otransit_msg(otmp, nodrop, chainthere, n);
if (nodrop) { if (nodrop) {
if (impact) if (impact)
@@ -1665,7 +1668,7 @@ boolean near_hero;
case MIGR_SSTAIRS: case MIGR_SSTAIRS:
if ((stway = stairway_find_from(&fromdlev, isladder)) != 0) { if ((stway = stairway_find_from(&fromdlev, isladder)) != 0) {
nx = stway->sx; nx = stway->sx;
nx = stway->sy; ny = stway->sy;
} }
break; break;
case MIGR_WITH_HERO: case MIGR_WITH_HERO:
@@ -1766,9 +1769,9 @@ unsigned long deliverflags;
} }
static void static void
otransit_msg(otmp, nodrop, num) otransit_msg(otmp, nodrop, chainthere, num)
register struct obj *otmp; register struct obj *otmp;
register boolean nodrop; boolean nodrop, chainthere;
long num; long num;
{ {
char *optr = 0, obuf[BUFSZ], xbuf[BUFSZ]; char *optr = 0, obuf[BUFSZ], xbuf[BUFSZ];
@@ -1782,11 +1785,15 @@ long num;
} }
Strcpy(obuf, optr); 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 /* As of 3.6.2: use a separate buffer for the suffix to avoid risk of
overrunning obuf[] (let pline() handle truncation if necessary) */ overrunning obuf[] (let pline() handle truncation if necessary) */
Sprintf(xbuf, " %s %s object%s", otense(otmp, "hit"), if (num) { /* means: other objects are impacted */
(num == 1L) ? "another" : "other", (num > 1L) ? "s" : ""); 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) if (nodrop)
Sprintf(eos(xbuf), "."); Sprintf(eos(xbuf), ".");
else else
+6 -5
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */ /* 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, static NEARDATA const char toss_objs[] = { ALLOW_COUNT, COIN_CLASS,
ALL_CLASSES, WEAPON_CLASS, 0 }; ALL_CLASSES, WEAPON_CLASS, 0 };
/* different default choices when wielding a sling (gold must be included) */ /* different default choices when wielding a sling (gold must be included) */
static NEARDATA const char bullets[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, static NEARDATA const char t_bullets[] = {
GEM_CLASS, 0 }; ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0
};
/* g.thrownobj (decl.c) tracks an object until it lands */ /* g.thrownobj (decl.c) tracks an object until it lands */
@@ -295,7 +296,7 @@ dothrow()
if (!ok_to_throw(&shotlimit)) if (!ok_to_throw(&shotlimit))
return 0; return 0;
obj = getobj(uslinging() ? bullets : toss_objs, "throw"); obj = getobj(uslinging() ? t_bullets : toss_objs, "throw");
/* it is also possible to throw food */ /* it is also possible to throw food */
/* (or jewels, or iron balls... ) */ /* (or jewels, or iron balls... ) */
@@ -407,7 +408,7 @@ dofire()
use direction of previous throw as getobj()'s choice here */ use direction of previous throw as getobj()'s choice here */
g.in_doagain = 0; g.in_doagain = 0;
/* choose something from inventory, then usually quiver it */ /* 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 */ /* Q command doesn't allow gold in quiver */
if (obj && !obj->owornmask && obj->oclass != COIN_CLASS) if (obj && !obj->owornmask && obj->oclass != COIN_CLASS)
setuqwep(obj); /* demi-autoquiver */ setuqwep(obj); /* demi-autoquiver */
+27 -601
View File
@@ -267,6 +267,7 @@ boolean quietly;
* / / / * / / /
* x x x * x x x
* *
* 0x8 MM_AGR_DONE
* 0x4 MM_AGR_DIED * 0x4 MM_AGR_DIED
* 0x2 MM_DEF_DIED * 0x2 MM_DEF_DIED
* 0x1 MM_HIT * 0x1 MM_HIT
@@ -367,7 +368,7 @@ register struct monst *magr, *mdef;
case AT_WEAP: /* "hand to hand" attacks */ case AT_WEAP: /* "hand to hand" attacks */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) { if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) {
/* D: Do a ranged attack here! */ /* D: Do a ranged attack here! */
strike = thrwmm(magr, mdef); strike = (thrwmm(magr, mdef) == MM_MISS) ? 0 : 1;
if (strike) if (strike)
/* don't really know if we hit or not; pretend we did */ /* don't really know if we hit or not; pretend we did */
res[i] |= MM_HIT; res[i] |= MM_HIT;
@@ -380,7 +381,7 @@ register struct monst *magr, *mdef;
if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) { if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
magr->weapon_check = NEED_HTH_WEAPON; magr->weapon_check = NEED_HTH_WEAPON;
if (mon_wield_item(magr) != 0) if (mon_wield_item(magr) != 0)
return 0; return MM_MISS;
} }
possibly_unwield(magr, FALSE); possibly_unwield(magr, FALSE);
if ((mwep = MON_WEP(magr)) != 0) { if ((mwep = MON_WEP(magr)) != 0) {
@@ -489,7 +490,7 @@ register struct monst *magr, *mdef;
case AT_BREA: case AT_BREA:
if (!monnear(magr, mdef->mx, mdef->my)) { 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. */ /* We don't really know if we hit or not; pretend we did. */
if (strike) if (strike)
@@ -505,7 +506,7 @@ register struct monst *magr, *mdef;
case AT_SPIT: case AT_SPIT:
if (!monnear(magr, mdef->mx, mdef->my)) { 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. */ /* We don't really know if we hit or not; pretend we did. */
if (strike) if (strike)
@@ -855,13 +856,16 @@ struct attack *mattk;
struct obj *mwep; struct obj *mwep;
int dieroll; int dieroll;
{ {
struct obj *obj;
char buf[BUFSZ];
struct permonst *pa = magr->data, *pd = mdef->data; struct permonst *pa = magr->data, *pd = mdef->data;
int armpro, num, int armpro;
tmp = d((int) mattk->damn, (int) mattk->damd),
res = MM_MISS;
boolean cancelled; 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() */ if ((touch_petrifies(pd) /* or flesh_petrifies() */
|| (mattk->adtyp == AD_DGST && pd == &mons[PM_MEDUSA])) || (mattk->adtyp == AD_DGST && pd == &mons[PM_MEDUSA]))
@@ -894,593 +898,14 @@ int dieroll;
armpro = magic_negation(mdef); armpro = magic_negation(mdef);
cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); cancelled = magr->mcan || !(rn2(10) >= 3 * armpro);
switch (mattk->adtyp) { mhitm_adtyping(magr, mattk, mdef, &mhm);
case AD_DGST: if (mhm.done)
/* eating a Rider or its corpse is fatal */ return mhm.hitflags;
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);
/* Is a corpse for nutrition possible? It may kill magr */ if (!mhm.damage)
if (!corpse_chance(mdef, magr, TRUE) || DEADMONSTER(magr)) return mhm.hitflags;
break;
/* Pets get nutrition from swallowing monster whole. if ((mdef->mhp -= mhm.damage) < 1) {
* 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 (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */ if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */
remove_monster(mdef->mx, mdef->my); remove_monster(mdef->mx, mdef->my);
mdef->mhp = 1; /* otherwise place_monster will complain */ mdef->mhp = 1; /* otherwise place_monster will complain */
@@ -1495,8 +920,8 @@ int dieroll;
monkilled(mdef, "", (int) mattk->adtyp); monkilled(mdef, "", (int) mattk->adtyp);
g.zombify = FALSE; /* reset */ g.zombify = FALSE; /* reset */
if (!DEADMONSTER(mdef)) if (!DEADMONSTER(mdef))
return res; /* mdef lifesaved */ return mhm.hitflags; /* mdef lifesaved */
else if (res == MM_AGR_DIED) else if (mhm.hitflags == MM_AGR_DIED)
return (MM_DEF_DIED | MM_AGR_DIED); return (MM_DEF_DIED | MM_AGR_DIED);
if (mattk->adtyp == AD_DGST) { if (mattk->adtyp == AD_DGST) {
@@ -1518,7 +943,7 @@ int dieroll;
return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); 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 int
@@ -1682,9 +1107,9 @@ struct obj *otemp;
* handled above. Returns same values as mattackm. * handled above. Returns same values as mattackm.
*/ */
static int static int
passivemm(magr, mdef, mhit, mdead, mwep) passivemm(magr, mdef, mhitb, mdead, mwep)
register struct monst *magr, *mdef; register struct monst *magr, *mdef;
boolean mhit; boolean mhitb;
int mdead; int mdead;
struct obj *mwep; struct obj *mwep;
{ {
@@ -1692,6 +1117,7 @@ struct obj *mwep;
register struct permonst *madat = magr->data; register struct permonst *madat = magr->data;
char buf[BUFSZ]; char buf[BUFSZ];
int i, tmp; int i, tmp;
int mhit = mhitb ? MM_HIT : MM_MISS;
for (i = 0;; i++) { for (i = 0;; i++) {
if (i >= NATTK) if (i >= NATTK)
@@ -1709,7 +1135,7 @@ struct obj *mwep;
/* These affect the enemy even if defender killed */ /* These affect the enemy even if defender killed */
switch (mddat->mattk[i].adtyp) { switch (mddat->mattk[i].adtyp) {
case AD_ACID: case AD_ACID:
if (mhit && !rn2(2)) { if (mhitb && !rn2(2)) {
Strcpy(buf, Monnam(magr)); Strcpy(buf, Monnam(magr));
if (canseemon(magr)) if (canseemon(magr))
pline("%s is splashed by %s %s!", buf, pline("%s is splashed by %s %s!", buf,
@@ -1727,7 +1153,7 @@ struct obj *mwep;
acid_damage(MON_WEP(magr)); acid_damage(MON_WEP(magr));
goto assess_dmg; goto assess_dmg;
case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
if (mhit && !mdef->mcan && mwep) { if (mhitb && !mdef->mcan && mwep) {
(void) drain_item(mwep, FALSE); (void) drain_item(mwep, FALSE);
/* No message */ /* No message */
} }
+60 -790
View File
File diff suppressed because it is too large Load Diff
-6
View File
@@ -1586,17 +1586,11 @@ struct monst *mtmp;
/* unicorn may not be able to avoid hero on a noteleport level */ /* unicorn may not be able to avoid hero on a noteleport level */
if (is_unicorn(mtmp->data) && !noteleport_level(mtmp)) if (is_unicorn(mtmp->data) && !noteleport_level(mtmp))
allowflags |= NOTONL; 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]) if (is_human(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR])
allowflags |= ALLOW_SSM; allowflags |= ALLOW_SSM;
if ((is_undead(mtmp->data) && mtmp->data->mlet != S_GHOST) if ((is_undead(mtmp->data) && mtmp->data->mlet != S_GHOST)
|| is_vampshifter(mtmp)) || is_vampshifter(mtmp))
allowflags |= NOGARLIC; allowflags |= NOGARLIC;
if (throws_rocks(mtmp->data))
allowflags |= ALLOW_ROCK;
return allowflags; return allowflags;
} }
+12 -12
View File
@@ -704,13 +704,13 @@ struct monst *mtmp, *mtarg;
mtmp->weapon_check = NEED_RANGED_WEAPON; mtmp->weapon_check = NEED_RANGED_WEAPON;
/* mon_wield_item resets weapon_check as appropriate */ /* mon_wield_item resets weapon_check as appropriate */
if (mon_wield_item(mtmp) != 0) if (mon_wield_item(mtmp) != 0)
return 0; return MM_MISS;
} }
/* Pick a weapon */ /* Pick a weapon */
otmp = select_rwep(mtmp); otmp = select_rwep(mtmp);
if (!otmp) if (!otmp)
return 0; return MM_MISS;
ispole = is_pole(otmp); ispole = is_pole(otmp);
x = mtmp->mx; x = mtmp->mx;
@@ -725,17 +725,17 @@ struct monst *mtmp, *mtarg;
if (ammo_and_launcher(otmp, mwep) if (ammo_and_launcher(otmp, mwep)
&& dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
> PET_MISSILE_RANGE2) > PET_MISSILE_RANGE2)
return 0; /* Out of range */ return MM_MISS; /* Out of range */
/* Set target monster */ /* Set target monster */
g.mtarget = mtarg; g.mtarget = mtarg;
g.marcher = mtmp; g.marcher = mtmp;
monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */ monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
g.marcher = g.mtarget = (struct monst *) 0; g.marcher = g.mtarget = (struct monst *) 0;
nomul(0); nomul(0);
return 1; return MM_HIT;
} }
} }
return 0; return MM_MISS;
} }
/* monster spits substance at monster */ /* monster spits substance at monster */
@@ -750,7 +750,7 @@ struct attack *mattk;
if (!Deaf) if (!Deaf)
pline("A dry rattle comes from %s throat.", pline("A dry rattle comes from %s throat.",
s_suffix(mon_nam(mtmp))); s_suffix(mon_nam(mtmp)));
return 0; return MM_MISS;
} }
if (m_lined_up(mtarg, mtmp)) { if (m_lined_up(mtarg, mtmp)) {
switch (mattk->adtyp) { switch (mattk->adtyp) {
@@ -759,7 +759,7 @@ struct attack *mattk;
otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
break; break;
default: default:
impossible("bad attack type in spitmu"); impossible("bad attack type in spitmm");
/*FALLTHRU*/ /*FALLTHRU*/
case AD_ACID: case AD_ACID:
otmp = mksobj(ACID_VENOM, TRUE, FALSE); otmp = mksobj(ACID_VENOM, TRUE, FALSE);
@@ -784,10 +784,10 @@ struct attack *mattk;
dog->hungrytime -= 5; dog->hungrytime -= 5;
} }
return 1; return MM_HIT;
} }
} }
return 0; return MM_MISS;
} }
/* monster breathes at monster (ranged) */ /* monster breathes at monster (ranged) */
@@ -807,7 +807,7 @@ struct attack *mattk;
else else
You_hear("a cough."); You_hear("a cough.");
} }
return 0; return MM_MISS;
} }
if (!mtmp->mspec_used && rn2(3)) { if (!mtmp->mspec_used && rn2(3)) {
if ((typ >= AD_MAGM) && (typ <= AD_ACID)) { if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
@@ -836,9 +836,9 @@ struct attack *mattk;
} }
} else impossible("Breath weapon %d used", typ-1); } else impossible("Breath weapon %d used", typ-1);
} else } else
return 0; return MM_MISS;
} }
return 1; return MM_HIT;
} }
+58 -27
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -214,8 +214,10 @@ struct obj *obj;
int int
doread() doread()
{ {
static const char find_any_braille[] = "feel any Braille writing.";
register struct obj *scroll; register struct obj *scroll;
boolean confused, nodisappear; boolean confused, nodisappear;
int otyp;
/* /*
* Reading while blind is allowed in most cases, including the * Reading while blind is allowed in most cases, including the
@@ -241,9 +243,10 @@ doread()
scroll = getobj(readable, "read"); scroll = getobj(readable, "read");
if (!scroll) if (!scroll)
return 0; return 0;
otyp = scroll->otyp;
/* outrumor has its own blindness check */ /* outrumor has its own blindness check */
if (scroll->otyp == FORTUNE_COOKIE) { if (otyp == FORTUNE_COOKIE) {
if (flags.verbose) if (flags.verbose)
You("break up the cookie and throw away the pieces."); You("break up the cookie and throw away the pieces.");
outrumor(bcsign(scroll), BY_COOKIE); outrumor(bcsign(scroll), BY_COOKIE);
@@ -251,16 +254,16 @@ doread()
u.uconduct.literate++; u.uconduct.literate++;
useup(scroll); useup(scroll);
return 1; return 1;
} else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) { } else if (otyp == T_SHIRT || otyp == ALCHEMY_SMOCK) {
char buf[BUFSZ], *mesg; char buf[BUFSZ], *mesg;
const char *endpunct; const char *endpunct;
if (Blind) { if (Blind) {
You_cant("feel any Braille writing."); You_cant(find_any_braille);
return 0; return 0;
} }
/* can't read shirt worn under suit (under cloak is ok though) */ /* 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.", pline("%s shirt is obscured by %s%s.",
scroll->unpaid ? "That" : "Your", shk_your(buf, uarm), scroll->unpaid ? "That" : "Your", shk_your(buf, uarm),
suit_simple_name(uarm)); suit_simple_name(uarm));
@@ -268,8 +271,8 @@ doread()
} }
u.uconduct.literate++; u.uconduct.literate++;
/* populate 'buf[]' */ /* populate 'buf[]' */
mesg = (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf) mesg = (otyp == T_SHIRT) ? tshirt_text(scroll, buf)
: apron_text(scroll, buf); : apron_text(scroll, buf);
endpunct = ""; endpunct = "";
if (flags.verbose) { if (flags.verbose) {
int ln = (int) strlen(mesg); int ln = (int) strlen(mesg);
@@ -281,7 +284,37 @@ doread()
} }
pline("\"%s\"%s", mesg, endpunct); pline("\"%s\"%s", mesg, endpunct);
return 1; 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[] = { static const char *card_msgs[] = {
"Leprechaun Gold Tru$t - Shamrock Card", "Leprechaun Gold Tru$t - Shamrock Card",
"Magic Memory Vault Charge Card", "Magic Memory Vault Charge Card",
@@ -320,12 +353,12 @@ doread()
(flags.verbose || Blind) ? "." : ""); (flags.verbose || Blind) ? "." : "");
u.uconduct.literate++; u.uconduct.literate++;
return 1; return 1;
} else if (scroll->otyp == CAN_OF_GREASE) { } else if (otyp == CAN_OF_GREASE) {
pline("This %s has no label.", singular(scroll, xname)); pline("This %s has no label.", singular(scroll, xname));
return 0; return 0;
} else if (scroll->otyp == MAGIC_MARKER) { } else if (otyp == MAGIC_MARKER) {
if (Blind) { if (Blind) {
You_cant("feel any Braille writing."); You_cant(find_any_braille);
return 0; return 0;
} }
if (flags.verbose) if (flags.verbose)
@@ -349,11 +382,11 @@ doread()
pline("\"Odin.\""); pline("\"Odin.\"");
u.uconduct.literate++; u.uconduct.literate++;
return 1; return 1;
} else if (scroll->otyp == CANDY_BAR) { } else if (otyp == CANDY_BAR) {
const char *wrapper = candy_wrapper_text(scroll); const char *wrapper = candy_wrapper_text(scroll);
if (Blind) { if (Blind) {
You_cant("feel any Braille writing."); You_cant(find_any_braille);
return 0; return 0;
} }
if (!*wrapper) { if (!*wrapper) {
@@ -367,10 +400,10 @@ doread()
&& scroll->oclass != SPBOOK_CLASS) { && scroll->oclass != SPBOOK_CLASS) {
pline(silly_thing_to, "read"); pline(silly_thing_to, "read");
return 0; 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; const char *what = 0;
if (scroll->otyp == SPE_NOVEL) if (otyp == SPE_NOVEL)
/* unseen novels are already distinguishable from unseen /* unseen novels are already distinguishable from unseen
spellbooks so this isn't revealing any extra information */ spellbooks so this isn't revealing any extra information */
what = "words"; what = "words";
@@ -386,7 +419,7 @@ doread()
confused = (Confusion != 0); confused = (Confusion != 0);
#ifdef MAIL #ifdef MAIL
if (scroll->otyp == SCR_MAIL) { if (otyp == SCR_MAIL) {
confused = FALSE; /* override */ confused = FALSE; /* override */
/* reading mail is a convenience for the player and takes /* reading mail is a convenience for the player and takes
place outside the game, so shouldn't affect gameplay; place outside the game, so shouldn't affect gameplay;
@@ -405,24 +438,22 @@ doread()
#endif #endif
/* Actions required to win the game aren't counted towards conduct */ /* Actions required to win the game aren't counted towards conduct */
/* Novel conduct is handled in read_tribute so exclude it too*/ /* Novel conduct is handled in read_tribute so exclude it too */
if (scroll->otyp != SPE_BOOK_OF_THE_DEAD if (otyp != SPE_BOOK_OF_THE_DEAD && otyp != SPE_NOVEL
&& scroll->otyp != SPE_BLANK_PAPER && scroll->otyp != SCR_BLANK_PAPER && otyp != SPE_BLANK_PAPER && otyp != SCR_BLANK_PAPER)
&& scroll->otyp != SPE_NOVEL)
u.uconduct.literate++; u.uconduct.literate++;
if (scroll->oclass == SPBOOK_CLASS) { if (scroll->oclass == SPBOOK_CLASS) {
return study_book(scroll); return study_book(scroll);
} }
scroll->in_use = TRUE; /* scroll, not spellbook, now being read */ 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); boolean silently = !can_chant(&g.youmonst);
/* a few scroll feedback messages describe something happening /* a few scroll feedback messages describe something happening
to the scroll itself, so avoid "it disappears" for those */ to the scroll itself, so avoid "it disappears" for those */
nodisappear = (scroll->otyp == SCR_FIRE nodisappear = (otyp == SCR_FIRE
|| (scroll->otyp == SCR_REMOVE_CURSE || (otyp == SCR_REMOVE_CURSE && scroll->cursed));
&& scroll->cursed));
if (Blind) if (Blind)
pline(nodisappear pline(nodisappear
? "You %s the formula on the scroll." ? "You %s the formula on the scroll."
@@ -440,14 +471,14 @@ doread()
} }
} }
if (!seffects(scroll)) { if (!seffects(scroll)) {
if (!objects[scroll->otyp].oc_name_known) { if (!objects[otyp].oc_name_known) {
if (g.known) if (g.known)
learnscroll(scroll); learnscroll(scroll);
else if (!objects[scroll->otyp].oc_uname) else if (!objects[otyp].oc_uname)
docall(scroll); docall(scroll);
} }
scroll->in_use = FALSE; scroll->in_use = FALSE;
if (scroll->otyp != SCR_BLANK_PAPER) if (otyp != SCR_BLANK_PAPER)
useup(scroll); useup(scroll);
} }
return 1; return 1;
+5 -2
View File
@@ -923,11 +923,14 @@ NHFILE *nhfp;
if (buflen == -1) if (buflen == -1)
break; break;
len += (int) sizeof (stairway);
if (nhfp->structlevel) { if (nhfp->structlevel) {
len += (int) sizeof (stairway);
mread(nhfp->fd, (genericptr_t) &stway, 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, stairway_add(stway.sx, stway.sy, stway.up, stway.isladder,
&(stway.tolev)); &(stway.tolev));
} }
+131 -75
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2009. */ /*-Copyright (c) Michael Allison, 2009. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -21,15 +21,12 @@ int dotcnt, dotrow; /* also used in restore */
#endif #endif
static void FDECL(savelevchn, (NHFILE *)); 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(savelevl, (NHFILE *,BOOLEAN_P));
static void FDECL(savedamage, (NHFILE *));
static void FDECL(save_stairs, (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(savemonchn, (NHFILE *,struct monst *));
static void FDECL(savetrapchn, (NHFILE *,struct trap *)); static void FDECL(savetrapchn, (NHFILE *,struct trap *));
static void FDECL(savegamestate, (NHFILE *)); static void FDECL(savegamestate, (NHFILE *));
@@ -86,7 +83,9 @@ dosave0()
d_level uz_save; d_level uz_save;
char whynot[BUFSZ]; char whynot[BUFSZ];
NHFILE *nhfp, *onhfp; 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 /* 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 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 */ an improper state; these will be no-ops for normal save sequence */
@@ -99,9 +98,9 @@ dosave0()
u.uburied = 1, iflags.save_uburied = 0; u.uburied = 1, iflags.save_uburied = 0;
if (!g.program_state.something_worth_saving || !g.SAVEF[0]) if (!g.program_state.something_worth_saving || !g.SAVEF[0])
return 0; goto done;
fq_save = fqname(g.SAVEF, SAVEPREFIX, 1); /* level files take 0 */
fq_save = fqname(g.SAVEF, SAVEPREFIX, 1); /* level files take 0 */
#ifndef NO_SIGNAL #ifndef NO_SIGNAL
#if defined(UNIX) || defined(VMS) #if defined(UNIX) || defined(VMS)
sethanguphandler((void FDECL((*), (int) )) SIG_IGN); sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
@@ -118,7 +117,7 @@ dosave0()
There("seems to be an old save file."); There("seems to be an old save file.");
if (yn("Overwrite the old file?") == 'n') { if (yn("Overwrite the old file?") == 'n') {
nh_compress(fq_save); nh_compress(fq_save);
return 0; goto done;
} }
} }
} }
@@ -129,7 +128,7 @@ dosave0()
if (!nhfp) { if (!nhfp) {
HUP pline("Cannot open save file."); HUP pline("Cannot open save file.");
(void) delete_savefile(); /* ab@unido */ (void) delete_savefile(); /* ab@unido */
return 0; goto done;
} }
vision_recalc(2); /* shut down vision to prevent problems vision_recalc(2); /* shut down vision to prevent problems
@@ -158,6 +157,15 @@ dosave0()
store_plname_in_file(nhfp); store_plname_in_file(nhfp);
g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
g.usteed_id = (u.usteed ? u.usteed->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)); savelev(nhfp, ledger_no(&u.uz));
savegamestate(nhfp); savegamestate(nhfp);
@@ -197,13 +205,13 @@ dosave0()
(void) delete_savefile(); (void) delete_savefile();
HUP Strcpy(g.killer.name, whynot); HUP Strcpy(g.killer.name, whynot);
HUP done(TRICKED); HUP done(TRICKED);
return 0; goto done;
} }
minit(); /* ZEROCOMP */ minit(); /* ZEROCOMP */
getlev(onhfp, g.hackpid, ltmp); getlev(onhfp, g.hackpid, ltmp);
close_nhfile(onhfp); close_nhfile(onhfp);
if (nhfp->structlevel) if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &ltmp, sizeof ltmp); /* level number*/ bwrite(nhfp->fd, (genericptr_t) &ltmp, sizeof ltmp); /* lvl no. */
savelev(nhfp, ltmp); /* actual level*/ savelev(nhfp, ltmp); /* actual level*/
delete_levelfile(ltmp); delete_levelfile(ltmp);
} }
@@ -217,7 +225,11 @@ dosave0()
nh_compress(fq_save); nh_compress(fq_save);
/* this should probably come sooner... */ /* this should probably come sooner... */
g.program_state.something_worth_saving = 0; g.program_state.something_worth_saving = 0;
return 1; res = 1;
done:
g.program_state.saving--;
return res;
} }
static void static void
@@ -225,8 +237,9 @@ savegamestate(nhfp)
NHFILE *nhfp; NHFILE *nhfp;
{ {
unsigned long uid; 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(); uid = (unsigned long) getuid();
if (nhfp->structlevel) { if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid); bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid);
@@ -251,27 +264,31 @@ NHFILE *nhfp;
save_timers(nhfp, RANGE_GLOBAL); save_timers(nhfp, RANGE_GLOBAL);
save_light_sources(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 /* save ball and chain if they are currently dangling free (i.e. not
floor or in inventory) */ on floor or in inventory); 'looseball' and 'loosechain' have been
if (CHAIN_IN_MON) { set up in caller because ball and chain will be gone by now if on
uchain->nobj = bc_objs; floor, or ball gone if carried; caveat: uball and uchain pointers
bc_objs = uchain; 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) { if (g.looseball) {
uball->nobj = bc_objs; g.looseball->nobj = bc_objs;
bc_objs = uball; 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); savemonchn(nhfp, g.migrating_mons);
if (release_data(nhfp)) { if (release_data(nhfp))
g.invent = 0; g.migrating_mons = (struct monst *) 0;
g.migrating_objs = 0;
g.migrating_mons = 0;
}
if (nhfp->structlevel) if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) g.mvitals, sizeof g.mvitals); bwrite(nhfp->fd, (genericptr_t) g.mvitals, sizeof g.mvitals);
save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp),
@@ -304,8 +321,11 @@ NHFILE *nhfp;
save_msghistory(nhfp); save_msghistory(nhfp);
if (nhfp->structlevel) if (nhfp->structlevel)
bflush(nhfp->fd); bflush(nhfp->fd);
g.program_state.saving--;
return;
} }
/* potentially called from goto_level(do.c) as well as savestateinlock() */
boolean boolean
tricked_fileremoved(nhfp, whynot) tricked_fileremoved(nhfp, whynot)
NHFILE *nhfp; NHFILE *nhfp;
@@ -329,6 +349,7 @@ savestateinlock()
char whynot[BUFSZ]; char whynot[BUFSZ];
NHFILE *nhfp; NHFILE *nhfp;
g.program_state.saving++; /* inhibit status and perm_invent updates */
/* When checkpointing is on, the full state needs to be written /* When checkpointing is on, the full state needs to be written
* on each checkpoint. When checkpointing is off, only the pid * 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 * 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 * readable by an external utility
*/ */
nhfp = open_levelfile(0, whynot); nhfp = open_levelfile(0, whynot);
if (tricked_fileremoved(nhfp, whynot)) if (tricked_fileremoved(nhfp, whynot)) {
g.program_state.saving--;
return; return;
}
if (nhfp->structlevel) if (nhfp->structlevel)
(void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid); (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid);
if (g.hackpid != hpid) { if (g.hackpid != hpid) {
Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!",
hpid, g.hackpid); hpid, g.hackpid);
pline1(whynot); goto giveup;
Strcpy(g.killer.name, whynot);
done(TRICKED);
} }
close_nhfile(nhfp); close_nhfile(nhfp);
nhfp = create_levelfile(0, whynot); nhfp = create_levelfile(0, whynot);
if (!nhfp) { if (!nhfp) {
pline1(whynot); pline1(whynot);
giveup:
Strcpy(g.killer.name, whynot); 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); done(TRICKED);
return; return;
} }
@@ -384,11 +412,15 @@ savestateinlock()
g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
g.usteed_id = (u.usteed ? u.usteed->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); savegamestate(nhfp);
} }
close_nhfile(nhfp); close_nhfile(nhfp);
} }
g.program_state.saving--;
g.havestate = flags.ins_chkpt; g.havestate = flags.ins_chkpt;
return;
} }
#endif #endif
@@ -401,6 +433,7 @@ xchar lev;
short tlev; short tlev;
#endif #endif
g.program_state.saving++; /* even if current mode is FREEING */
/* /*
* Level file contents: * Level file contents:
* version info (handled by caller); * version info (handled by caller);
@@ -454,7 +487,8 @@ xchar lev;
if (nhfp->mode == FREEING) /* see above */ if (nhfp->mode == FREEING) /* see above */
goto skip_lots; goto skip_lots;
savelevl(nhfp, (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); savelevl(nhfp,
(boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
if (nhfp->structlevel) { if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) g.lastseentyp, sizeof g.lastseentyp); bwrite(nhfp->fd, (genericptr_t) g.lastseentyp, sizeof g.lastseentyp);
bwrite(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves); bwrite(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
@@ -475,9 +509,9 @@ xchar lev;
savemonchn(nhfp, fmon); savemonchn(nhfp, fmon);
save_worm(nhfp); /* save worm information */ save_worm(nhfp); /* save worm information */
savetrapchn(nhfp, g.ftrap); savetrapchn(nhfp, g.ftrap);
saveobjchn(nhfp, fobj); saveobjchn(nhfp, &fobj);
saveobjchn(nhfp, g.level.buriedobjlist); saveobjchn(nhfp, &g.level.buriedobjlist);
saveobjchn(nhfp, g.billobjs); saveobjchn(nhfp, &g.billobjs);
if (release_data(nhfp)) { if (release_data(nhfp)) {
int x,y; int x,y;
/* TODO: maybe use clear_level_structures() */ /* TODO: maybe use clear_level_structures() */
@@ -503,6 +537,8 @@ xchar lev;
if (nhfp->structlevel) if (nhfp->structlevel)
bflush(nhfp->fd); bflush(nhfp->fd);
} }
g.program_state.saving--;
return;
} }
static void static void
@@ -564,6 +600,7 @@ boolean rlecomp;
if (nhfp->structlevel) { if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) levl, sizeof levl); bwrite(nhfp->fd, (genericptr_t) levl, sizeof levl);
} }
return;
} }
/* used when saving a level and also when saving dungeon overview data */ /* used when saving a level and also when saving dungeon overview data */
@@ -622,6 +659,40 @@ NHFILE *nhfp;
g.level.damagelist = 0; 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 static void
saveobj(nhfp, otmp) saveobj(nhfp, otmp)
NHFILE *nhfp; NHFILE *nhfp;
@@ -660,46 +731,22 @@ struct obj *otmp;
} }
/* omid used to be indirect via a pointer in oextra but has /* omid used to be indirect via a pointer in oextra but has
become part of oextra itself; 0 means not applicable and 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) if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp)); 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 static void
save_stairs(nhfp) saveobjchn(nhfp, obj_p)
NHFILE *nhfp; NHFILE *nhfp;
struct obj **obj_p;
{ {
stairway *stway = g.stairs; register struct obj *otmp = *obj_p;
int buflen = (int) sizeof (stairway); struct obj *otmp2;
int len = 0; boolean is_invent = (otmp && otmp == g.invent);
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;
int minusone = -1; int minusone = -1;
while (otmp) { while (otmp) {
@@ -708,7 +755,7 @@ register struct obj *otmp;
saveobj(nhfp, otmp); saveobj(nhfp, otmp);
} }
if (Has_contents(otmp)) if (Has_contents(otmp))
saveobjchn(nhfp, otmp->cobj); saveobjchn(nhfp, &otmp->cobj);
if (release_data(nhfp)) { if (release_data(nhfp)) {
/* /*
* If these are on the floor, the discarding could be * 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->cobj = NULL; /* contents handled above */
otmp->timed = 0; /* not timed any more */ otmp->timed = 0; /* not timed any more */
otmp->lamplit = 0; /* caller handled lights */ 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); dealloc_obj(otmp);
} }
otmp = otmp2; otmp = otmp2;
@@ -741,6 +792,11 @@ register struct obj *otmp;
if (nhfp->structlevel) if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int)); 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 static void
@@ -825,7 +881,7 @@ register struct monst *mtmp;
savemon(nhfp, mtmp); savemon(nhfp, mtmp);
} }
if (mtmp->minvent) if (mtmp->minvent)
saveobjchn(nhfp, mtmp->minvent); saveobjchn(nhfp, &mtmp->minvent);
if (release_data(nhfp)) { if (release_data(nhfp)) {
if (mtmp == g.context.polearm.hitmon) { if (mtmp == g.context.polearm.hitmon) {
g.context.polearm.m_id = mtmp->m_id; g.context.polearm.m_id = mtmp->m_id;
@@ -1033,7 +1089,7 @@ freedynamicdata()
tmp_at(DISP_FREEMEM, 0); /* temporary display effects */ tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
#ifdef FREE_ALL_MEMORY #ifdef FREE_ALL_MEMORY
#define free_current_level() savelev(&tnhfp, -1) #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 freemonchn(X) (savemonchn(&tnhfp, X), X = 0)
#define freefruitchn() savefruitchn(&tnhfp) #define freefruitchn() savefruitchn(&tnhfp)
#define freenames() savenames(&tnhfp) #define freenames() savenames(&tnhfp)
+2382 -274
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2009. */ /*-Copyright (c) Robert Patrick Rankin, 2009. */
/* NetHack may be freely redistributed. See license for details. */ /* 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[] = { static NEARDATA const char ready_objs[] = {
ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0 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, ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE,
GEM_CLASS, WEAPON_CLASS, 0 GEM_CLASS, WEAPON_CLASS, 0
}; };
@@ -455,7 +455,7 @@ dowieldquiver()
quivee_types = (uslinging() quivee_types = (uslinging()
|| (uswapwep || (uswapwep
&& objects[uswapwep->otyp].oc_skill == P_SLING)) && objects[uswapwep->otyp].oc_skill == P_SLING))
? bullets ? w_bullets
: ready_objs; : ready_objs;
newquiver = getobj(quivee_types, "ready"); newquiver = getobj(quivee_types, "ready");
+20 -2
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */ /* 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) */ is pending (via 'A' command for multiple items) */
cancel_doff(obj, wp->w_mask); cancel_doff(obj, wp->w_mask);
*(wp->w_obj) = 0; *(wp->w_obj) = (struct obj *) 0;
p = objects[obj->otyp].oc_oprop; p = objects[obj->otyp].oc_oprop;
u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
obj->owornmask &= ~wp->w_mask; obj->owornmask &= ~wp->w_mask;
@@ -145,6 +145,24 @@ register struct obj *obj;
update_inventory(); 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() */ /* return item worn in slot indiciated by wornmask; needed by poly_obj() */
struct obj * struct obj *
wearmask_to_obj(wornmask) wearmask_to_obj(wornmask)
+26
View File
@@ -1192,6 +1192,32 @@ $(O)envchk.tag: $(O)obj.tag
#========================================== #==========================================
#=========== SECONDARY TARGETS ============ #=========== 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 # DLB utility and nhdatNNN file creation
+24 -10
View File
@@ -167,26 +167,40 @@ void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event)
if (promptstr != "#") if (promptstr != "#")
prompt->setText(promptstr.left(promptstr.size() - 1)); prompt->setText(promptstr.left(promptstr.size() - 1));
enableButtons(); enableButtons();
/*} else if (uc == '\r' || uc == '\n'; || uc == ' ') {*/ } else if ((uc < ' ' && !(uc == '\n' || uc == '\r'))
} else if (uc < ' ' || uc > std::max('z', 'Z')) { || uc > std::max('z', 'Z')) {
reject(); // done() reject(); // done()
} else { } 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 '#' QString typedstr = promptstr.mid(1); // skip the '#'
unsigned matches = 0; unsigned matches = 0;
unsigned match = 0; unsigned matchindx = 0;
for (unsigned i=0; extcmdlist[i].ef_txt; i++) { for (unsigned i=0; extcmdlist[i].ef_txt; i++) {
if (!interesting_command(i)) if (!interesting_command(i))
continue; continue;
if (QString(extcmdlist[i].ef_txt).startsWith(typedstr)) { QString cmdtxt = QString(extcmdlist[i].ef_txt);
++matches; if (cmdtxt.startsWith(typedstr)) {
if (matches >= 2) if (checkexact) {
break; if (cmdtxt == typedstr) {
match = i; matchindx = i;
matches = 1;
break;
}
} else {
if (++matches >= 2)
break;
matchindx = i;
}
} }
} }
if (matches == 1) if (matches == 1)
done(match+1); done(matchindx + 1);
else if (checkexact)
reject();
else if (matches >= 2) else if (matches >= 2)
prompt->setText(promptstr); prompt->setText(promptstr);
enableButtons(); enableButtons();