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

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
-----------------------------------
@@ -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

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) 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' */

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. */
/* 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 *));

View File

@@ -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 */

View File

@@ -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.

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) 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",

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) 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 */

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 */
/* 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)

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(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

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) 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 */

View File

@@ -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 */
}

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -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;
}

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) 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;

View File

@@ -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));
}

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) 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) &ltmp, sizeof ltmp); /* level number*/
bwrite(nhfp->fd, (genericptr_t) &ltmp, 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)

File diff suppressed because it is too large Load Diff

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) 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");

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) 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)

View File

@@ -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

View File

@@ -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();