Merge remote-tracking branch 'origin/NetHack-3.6.0'

This commit is contained in:
keni
2016-07-04 20:17:43 -04:00
25 changed files with 358 additions and 134 deletions

View File

@@ -570,9 +570,23 @@ Figure 2
Go in that direction until you hit a wall or run into something.
.lp m[yuhjklbn]
Prefix: move without picking up objects or fighting (even if you remember
a monster there)
a monster there).
.lp ""
A few non-movement commands use the `m' prefix to request operating
via menu (to temporarily override the
.op menustyle:Traditional
option).
Primarily useful for `,' (pickup) when there is only one class of
objects present (where there won't be any ``what kinds of objects?'' prompt,
so no opportunity to answer `m' at that prompt).
.lp ""
A few other commands (eat food, offer sacrifice, apply tinning-kit) use
the `m' prefix to skip checking for applicable objects on the floor
and go straight to checking inventory,
or (for ``#loot'' to remove a saddle),
skip containers and go straight to adjacent monsters.
.lp F[yuhjklbn]
Prefix: fight a monster (even if you only guess one is there)
Prefix: fight a monster (even if you only guess one is there).
.lp M[yuhjklbn]
Prefix: move far, no pickup.
.lp "g[yuhjklbn]
@@ -640,6 +654,11 @@ D%u - drop only unpaid food.
Kick something (usually a door).
.lp e
Eat food.
.lp ""
Normally checks for edible item(s) on the floor, then if none are found
or none are chosen, checks for edible item(s) in inventory.
Precede `e' with the `m' prefix to bypass attempting to eat
anything off the floor.
.\" Make sure Elbereth is not hyphenated below, the exact spelling matters
.hw Elbereth
.lp E
@@ -928,6 +947,8 @@ Kick something.
.lp #loot
Loot a box or bag on the floor beneath you, or the saddle
from a steed standing next to you.
Precede with the `m' prefix to skip containers at your location
and go directly to removing a saddle.
.lp #monster
Use a monster's special ability (when polymorphed into monster form).
.lp #name
@@ -1286,13 +1307,21 @@ have the right equipment and skill. Convincing a wild beast to let
you saddle it up is difficult to say the least. Many a dungeoneer
has had to resort to magic and wizardry in order to forge the alliance.
Once you do have the beast under your control however, you can
easily climb in and out of the saddle with the `#ride' command. Lead
easily climb in and out of the saddle with the ``#ride'' command. Lead
the beast around the dungeon when riding, in the same manner as
you would move yourself. It is the beast that you will see displayed
on the map.
.pg
Riding skill is managed by the `#enhance' command. See the section
Riding skill is managed by the ``#enhance'' command. See the section
on Weapon proficiency for more information about that.
.pg
Use the `a' (apply) command and pick a saddle in your inventory to
attempt to put that saddle on an adjacent creature. If successful,
it will be transferred to that creature's inventory.
.pg
Use the ``#loot'' command while adjacent to a saddled creature to
try to remove the saddle from that creature. If successful, it will
be transferred to your inventory.
.hn 2
Bones levels
.pg

View File

@@ -690,10 +690,24 @@ Go in that direction until you hit a wall or run into something.
%.lp
\item[\tb{m[yuhjklbn]}]
Prefix: move without picking up objects or fighting (even if you remember
a monster there)
a monster there).\\
%.lp ""
A few non-movement commands use the `{\tt m}' prefix to request operating
via menu (to temporarily override the
{\it menustyle:Traditional\/}
option).
Primarily useful for `{\tt ,}' (pickup) when there is only one class of
objects present (where there won't be any ``what kinds of objects?'' prompt,
so no opportunity to answer `{\tt m}' at that prompt).\\
%.lp ""
A few other commands (eat food, offer sacrifice, apply tinning-kit) use
the `{\tt m}' prefix to skip checking for applicable objects on the floor
and go straight to checking inventory,
or (for ``{\tt \#loot}'' to remove a saddle),
skip containers and go straight to adjacent monsters.
%.lp
\item[\tb{F[yuhjklbn]}]
Prefix: fight a monster (even if you only guess one is there)
Prefix: fight a monster (even if you only guess one is there).
%.lp
\item[\tb{M[yuhjklbn]}]
Prefix: Move far, no pickup.
@@ -775,7 +789,12 @@ the bless\-ed/\-un\-curs\-ed/\-curs\-ed groups may be typed.\\
Kick something (usually a door).
%.lp
\item[\tb{e}]
Eat food.
Eat food.\\
%.lp ""
Normally checks for edible item(s) on the floor, then if none are found
or none are chosen, checks for edible item(s) in inventory.
Precede `{\tt e}' with the `{\tt m}' prefix to bypass attempting to eat
anything off the floor.
%.lp
% Make sure Elbereth is not hyphenated below, the exact spelling matters.
% (Only specified here to parallel Guidebook.mn; use of \tt font implicity
@@ -1119,6 +1138,8 @@ Kick something.
\item[\tb{\#loot}]
Loot a box or bag on the floor beneath you, or the saddle
from a steed standing next to you.
Precede with the `{\tt m}' prefix to skip containers at your location
and go directly to removing a saddle.
%.lp
\item[\tb{\#monster}]
Use a monster's special ability (when polymorphed into monster form).
@@ -1574,15 +1595,25 @@ have the right equipment and skill. Convincing a wild beast to let
you saddle it up is difficult to say the least. Many a dungeoneer
has had to resort to magic and wizardry in order to forge the alliance.
Once you do have the beast under your control however, you can
easily climb in and out of the saddle with the `{\tt \#ride}' command. Lead
easily climb in and out of the saddle with the ``{\tt \#ride}'' command. Lead
the beast around the dungeon when riding, in the same manner as
you would move yourself. It is the beast that you will see displayed
on the map.
%.pg
Riding skill is managed by the `{\tt \#enhance}' command. See the section
Riding skill is managed by the ``{\tt \#enhance}'' command. See the section
on Weapon proficiency for more information about that.
%.pg
Use the `{\tt a}' (apply) command and pick a saddle in your inventory to
attempt to put that saddle on an adjacent creature. If successful,
it will be transferred to that creature's inventory.
%.pg
Use the ``{\tt \#loot}'' command while adjacent to a saddled creature to
try to remove the saddle from that creature. If successful, it will
be transferred to your inventory.
%.hn 2
\subsection*{Bones levels}

View File

@@ -302,6 +302,16 @@ conduct: wishing for an artifact and not getting it because it already exists
avoid ring of poison resistance as starting equipment for orcish wizard
gelatinous cube shouldn't be able to eat a scroll of scare monster
make fireballs or cones of cold cast a skilled or higher not go through walls
prevent flying monsters from hovering over unreachable underwater objects
lembas wafer gives increased nutrition to elves, reduced nutrition to orcs;
cram ration gives increase nutrition to dwarves
when #tip's terse object drop format got interrupted by a regular message,
it continued using "obj2, obj3, ..." for subsequent objects, where
the sentence grammar no longer made sense (the interrupting message
still follows the comma of a partial sentence--attempting to fix that
seems hopeless; leaving it is better than always using verbose format)
for #tip inside shop, credit was incorrectly given for spilled gold if that
gold's stale location coordinates didn't happen to be inside the shop
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
@@ -322,6 +332,7 @@ when picking a destination for #jump, '$' to show valid dest. is more accurate
Platform- and/or Interface-Specific Fixes
-----------------------------------------
tiles: wrinkled spellbook had a spurious brown pixel on far right edge of tile
tty: M-N gave "Unknown command 'M-" with "'." finishing the sentence on the
line below it, leaving bogus '.' displayed on the top row of the map
tty: specifying all four of role, race, gender, and alignment still prompted
@@ -337,6 +348,8 @@ tty: if color is disabled and use_inverse is enabled, display lava in inverse
tty: if "--More--" was written to leftmost column (beginning of second line)
while hero was swallowed, cursor would end up in wrong place (at end
of status line instead back on map) after message line was cleared
tty: long message lines which wrap when shown on the top line might be
re-displayed incorrectly by ^P for msg_window={full,combo,reverse}
unix/X11: in top level Makefile, some commented out definitions of VARDATND
misspelled pilemark.xbm (as pilemark.xpm)
unix: options file with CR+LF line ends and an invalid option line resulted in
@@ -365,6 +378,7 @@ X11: support pre-selected entries in menu windows
X11: make the extended command menu be easier to use and look a little nicer
X11: make the getline text entry widget display a bigger text entry area
X11: color didn't work when the map was displayed as text rather than tiles
X11: use grayscale monster tiles for statues
General New Features

View File

@@ -382,6 +382,7 @@ extern NEARDATA struct instance_flags iflags;
#define PLNMSG_TOWER_OF_FLAME 2 /* scroll of fire */
#define PLNMSG_CAUGHT_IN_EXPLOSION 3 /* explode() feedback */
#define PLNMSG_OBJ_GLOWS 4 /* "the <obj> glows <color>" */
#define PLNMSG_OBJNAM_ONLY 5 /* xname/doname only, for #tip */
/* Usage:
* pline("some message");
* pline: vsprintf + putstr + iflags.last_msg = PLNMSG_UNKNOWN;

View File

@@ -193,10 +193,18 @@
(vegan(ptr) \
|| ((ptr)->mlet == S_PUDDING && (ptr) != &mons[PM_BLACK_PUDDING]))
/* monkeys are tameable via bananas but not pacifiable via food,
otherwise their theft attack could be nullified too easily;
dogs and cats can be tamed by anything they like to eat and are
pacified by any other food;
horses can be tamed by always-veggy food or lichen corpses but
not tamed or pacified by other corpses or tins of veggy critters */
#define befriend_with_obj(ptr, obj) \
(((obj)->oclass == FOOD_CLASS && is_domestic(ptr)) \
|| ((obj)->otyp == BANANA && \
((ptr) == &mons[PM_MONKEY] \
|| (ptr) == &mons[PM_APE])))
(((ptr) == &mons[PM_MONKEY] || (ptr) == &mons[PM_APE]) \
? (obj)->otyp == BANANA \
: (is_domestic(ptr) && (obj)->oclass == FOOD_CLASS \
&& ((ptr)->mlet != S_UNICORN \
|| objects[(obj)->otyp].oc_material == VEGGY \
|| ((obj)->otyp == CORPSE && (obj)->corpsenm == PM_LICHEN))))
#endif /* MONDATA_H */

View File

@@ -3445,11 +3445,20 @@ boolean initial;
Cmd.move_SW = Cmd.dirchars[7];
}
/* non-movement commands which accept 'm' prefix to request menu operation */
STATIC_OVL boolean
accept_menu_prefix(cmd_func)
int NDECL((*cmd_func));
{
if (cmd_func == dopickup || cmd_func == dotip
/* eat, #offer, and apply tinning-kit all use floorfood() to pick
an item on floor or in invent; 'm' skips picking from floor
(ie, inventory only) rather than request use of menu operation */
|| cmd_func == doeat || cmd_func == dosacrifice || cmd_func == doapply
/* 'm' for removing saddle from adjacent monster without checking
for containers at <u.ux,u.uy> */
|| cmd_func == doloot
/* 'm' prefix allowed for some extended commands */
|| cmd_func == doextcmd || cmd_func == doextlist)
return TRUE;
return FALSE;

View File

@@ -814,8 +814,8 @@ register struct obj *obj;
case CARROT:
return herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD;
case BANANA:
return (mptr->mlet == S_YETI)
? DOGFOOD
return (mptr->mlet == S_YETI && herbi)
? DOGFOOD /* for monkey and ape (tameable), sasquatch */
: (herbi || starving)
? ACCFOOD
: MANFOOD;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 eat.c $NHDT-Date: 1466289475 2016/06/18 22:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.169 $ */
/* NetHack 3.6 eat.c $NHDT-Date: 1467028559 2016/06/27 11:55:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.171 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -13,6 +13,7 @@ STATIC_PTR int NDECL(unfaint);
STATIC_DCL const char *FDECL(food_xname, (struct obj *, BOOLEAN_P));
STATIC_DCL void FDECL(choke, (struct obj *));
STATIC_DCL void NDECL(recalc_wt);
STATIC_DCL unsigned FDECL(obj_nutrition, (struct obj *));
STATIC_DCL struct obj *FDECL(touchfood, (struct obj *));
STATIC_DCL void NDECL(do_reset_eat);
STATIC_DCL void FDECL(done_eating, (BOOLEAN_P));
@@ -296,6 +297,32 @@ reset_eat()
return;
}
/* base nutrition of a food-class object */
STATIC_OVL unsigned
obj_nutrition(otmp)
struct obj *otmp;
{
unsigned nut = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit
: otmp->globby ? otmp->owt
: (unsigned) objects[otmp->otyp].oc_nutrition;
if (otmp->otyp == LEMBAS_WAFER) {
if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF)))
nut += nut / 4; /* 800 -> 1000 */
else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
nut -= nut / 4; /* 800 -> 600 */
/* prevent polymorph making a partly eaten wafer
become more nutritious than an untouched one */
if (otmp->oeaten >= nut)
otmp->oeaten = (otmp->oeaten < objects[LEMBAS_WAFER].oc_nutrition)
? (nut - 1) : nut;
} else if (otmp->otyp == CRAM_RATION) {
if (maybe_polyd(is_dwarf(youmonst.data), Race_if(PM_DWARF)))
nut += nut / 6; /* 600 -> 700 */
}
return nut;
}
STATIC_OVL struct obj *
touchfood(otmp)
struct obj *otmp;
@@ -310,9 +337,7 @@ struct obj *otmp;
if (!otmp->oeaten) {
costly_alteration(otmp, COST_BITE);
otmp->oeaten = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit
: otmp->globby ? otmp->owt
: (unsigned) objects[otmp->otyp].oc_nutrition;
otmp->oeaten = obj_nutrition(otmp);
}
if (carried(otmp)) {
@@ -1741,6 +1766,15 @@ struct obj *otmp;
make_vomiting((long) rn1(context.victual.reqtime, 14), FALSE);
}
break;
case LEMBAS_WAFER:
if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) {
pline("%s", "!#?&* elf kibble!");
break;
} else if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) {
pline("A little goes a long way.");
break;
}
goto give_feedback;
case MEATBALL:
case MEAT_STICK:
case HUGE_CHUNK_OF_MEAT:
@@ -2368,6 +2402,7 @@ doeat()
if (u.uedibility) {
int res = edibility_prompts(otmp);
if (res) {
Your(
"%s stops tingling and your sense of smell returns to normal.",
@@ -2577,9 +2612,7 @@ doeat()
}
/* re-calc the nutrition */
basenutrit = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit
: otmp->globby ? otmp->owt
: (unsigned) objects[otmp->otyp].oc_nutrition;
basenutrit = (int) obj_nutrition(otmp);
debugpline3(
"before rounddiv: victual.reqtime == %d, oeaten == %d, basenutrit == %d",
@@ -2974,7 +3007,8 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */
/* if we can't touch floor objects then use invent food only */
if (!can_reach_floor(TRUE) || (feeding && u.usteed)
if (iflags.menu_requested /* command was preceded by 'm' prefix */
|| !can_reach_floor(TRUE) || (feeding && u.usteed)
|| (is_pool_or_lava(u.ux, u.uy)
&& (Wwalking || is_clinger(youmonst.data)
|| (Flying && !Breathless))))
@@ -3085,10 +3119,9 @@ struct obj *obj;
{
long uneaten_amt, full_amount;
/* get full_amount first; obj_nutrition() might modify obj->oeaten */
full_amount = (long) obj_nutrition(obj);
uneaten_amt = (long) obj->oeaten;
full_amount = (long) ((obj->otyp == CORPSE) ? mons[obj->corpsenm].cnutrit
: obj->globby ? obj->owt
: (unsigned) objects[obj->otyp].oc_nutrition);
if (uneaten_amt > full_amount) {
impossible(
"partly eaten food (%ld) more nutritious than untouched food (%ld)",

View File

@@ -979,15 +979,21 @@ not_special:
* mpickstuff() as well.
*/
if (xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) {
/* don't get stuck circling around an object that's
underneath
an immobile or hidden monster; paralysis victims
excluded */
/* don't get stuck circling around object that's
underneath an immobile or hidden monster;
paralysis victims excluded */
if ((mtoo = m_at(xx, yy)) != 0
&& (mtoo->msleeping || mtoo->mundetected
|| (mtoo->mappearance && !mtoo->iswiz)
|| !mtoo->data->mmove))
continue;
/* the mfndpos() test for whether to allow a move to a
water location accepts flyers, but they can't reach
underwater objects, so being able to move to a spot
is insufficient for deciding whether to do so */
if ((is_pool(xx, yy) && !is_swimmer(ptr))
|| (is_lava(xx, yy) && !likes_lava(ptr)))
continue;
if (((likegold && otmp->oclass == COIN_CLASS)
|| (likeobjs && index(practical, otmp->oclass)

View File

@@ -1923,16 +1923,18 @@ struct permonst _mons2[] = {
/*
* Apelike beasts
*/
/* tameable via banana; does not grow up into ape...
not flagged as domestic, so no guilt penalty for eating non-pet one */
MON("monkey", S_YETI, LVL(2, 12, 6, 0, 0), (G_GENO | 1),
A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(100, 50, MS_GROWL, MZ_SMALL), 0, 0,
M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, 0, M3_INFRAVISIBLE, CLR_GRAY),
M1_ANIMAL | M1_HUMANOID | M1_OMNIVORE, 0, M3_INFRAVISIBLE, CLR_GRAY),
MON("ape", S_YETI, LVL(4, 12, 6, 0, 0), (G_GENO | G_SGROUP | 2),
A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3),
ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(1100, 500, MS_GROWL, MZ_LARGE), 0, 0,
M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE,
M1_ANIMAL | M1_HUMANOID | M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE,
CLR_BROWN),
MON("owlbear", S_YETI, LVL(5, 12, 5, 0, 0), (G_GENO | 3),
A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6),

View File

@@ -414,6 +414,24 @@ boolean verbose; /* give message(s) even when you can't see what happened */
return 0;
}
#define MT_FLIGHTCHECK(pre) \
(/* missile hits edge of screen */ \
!isok(bhitpos.x + dx, bhitpos.y + dy) \
/* missile hits the wall */ \
|| IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) \
/* missile hit closed door */ \
|| closed_door(bhitpos.x + dx, bhitpos.y + dy) \
/* missile might hit iron bars */ \
/* the random chance for small objects hitting bars is */ \
/* skipped when reaching them at point blank range */ \
|| (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS \
&& hits_bars(&singleobj, \
bhitpos.x, bhitpos.y, \
bhitpos.x + dx, bhitpos.y + dy, \
((pre) ? 0 : !rn2(5)), 0)) \
/* Thrown objects "sink" */ \
|| (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ)))
void
m_throw(mon, x, y, dx, dy, range, obj)
struct monst *mon; /* launching monster */
@@ -471,17 +489,7 @@ struct obj *obj; /* missile (or stack providing it) */
}
}
/* pre-check for doors, walls and boundaries.
Also need to pre-check for bars regardless of direction;
the random chance for small objects hitting bars is
skipped when reaching them at point blank range */
if (!isok(bhitpos.x + dx, bhitpos.y + dy)
|| IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)
|| closed_door(bhitpos.x + dx, bhitpos.y + dy)
|| (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS
&& hits_bars(&singleobj,
bhitpos.x, bhitpos.y,
bhitpos.x + dx, bhitpos.y + dy, 0, 0))) {
if (MT_FLIGHTCHECK(TRUE)) {
(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
return;
}
@@ -611,20 +619,7 @@ struct obj *obj; /* missile (or stack providing it) */
}
}
if (!range /* reached end of path */
/* missile hits edge of screen */
|| !isok(bhitpos.x + dx, bhitpos.y + dy)
/* missile hits the wall */
|| IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)
/* missile hit closed door */
|| closed_door(bhitpos.x + dx, bhitpos.y + dy)
/* missile might hit iron bars */
|| (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS
&& hits_bars(&singleobj,
bhitpos.x, bhitpos.y,
bhitpos.x + dx, bhitpos.y + dy,
!rn2(5), 0))
/* Thrown objects "sink" */
|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
|| MT_FLIGHTCHECK(FALSE)) {
if (singleobj) { /* hits_bars might have destroyed it */
if (m_shot.n > 1 && (cansee(bhitpos.x, bhitpos.y)
|| (archer && canseemon(archer))))
@@ -648,6 +643,8 @@ struct obj *obj; /* missile (or stack providing it) */
}
}
#undef MT_FLIGHTCHECK
/* Monster throws item at another monster */
int
thrwmm(mtmp, mtarg)

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 pager.c $NHDT-Date: 1465114189 2016/06/05 08:09:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.107 $ */
/* NetHack 3.6 pager.c $NHDT-Date: 1466638086 2016/06/22 23:28:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.111 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1307,6 +1307,35 @@ doidtrap()
return 0;
}
/*
Implements a rudimentary if/elif/else/endif interpretor and use
conditionals in dat/cmdhelp to describe what command each keystroke
currently invokes, so that there isn't a lot of "(debug mode only)"
and "(if number_pad is off)" cluttering the feedback that the user
sees. (The conditionals add quite a bit of clutter to the raw data
but users don't see that. number_pad produces a lot of conditional
commands: basic letters vs digits, 'g' vs 'G' for '5', phone
keypad vs normal layout of digits, and QWERTZ keyboard swap between
y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
The interpretor understands
'&#' for comment,
'&? option' for 'if' (also '&? !option'
or '&? option=value[,value2,...]'
or '&? !option=value[,value2,...]'),
'&: option' for 'elif' (with argument variations same as 'if';
any number of instances for each 'if'),
'&:' for 'else' (also '&: #comment';
0 or 1 instance for a given 'if'), and
'&.' for 'endif' (also '&. #comment'; required for each 'if').
The option handling is a bit of a mess, with no generality for
which options to deal with and only a comma separated list of
integer values for the '=value' part. number_pad is the only
supported option that has a value; the few others (wizard/debug,
rest_on_space, #if SHELL, #if SUSPEND) are booleans.
*/
STATIC_DCL void
whatdoes_help()
{

View File

@@ -1630,7 +1630,7 @@ doloot()
char qbuf[BUFSZ];
int prev_inquiry = 0;
boolean prev_loot = FALSE;
int num_conts;
int num_conts = 0;
abort_looting = FALSE;
@@ -1653,13 +1653,30 @@ doloot()
cc.x = u.ux;
cc.y = u.uy;
lootcont:
if (iflags.menu_requested)
goto lootmon;
lootcont:
if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) {
boolean anyfound = FALSE;
if (!able_to_loot(cc.x, cc.y, TRUE))
return 0;
if (Blind && !uarmg) {
/* if blind and without gloves, attempting to #loot at the
location of a cockatrice corpse is fatal before asking
whether to manipulate any containers */
for (nobj = sobj_at(CORPSE, cc.x, cc.y); nobj;
nobj = nxtobj(nobj, CORPSE, TRUE))
if (will_feel_cockatrice(nobj, FALSE)) {
feel_cockatrice(nobj, FALSE);
/* if life-saved (or poly'd into stone golem),
terminate attempt to loot */
return 1;
}
}
if (num_conts > 1) {
/* use a menu to loot many containers */
int n, i;
@@ -1722,9 +1739,11 @@ lootcont:
} else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
You("need to dig up the grave to effectively loot it...");
}
/*
* 3.3.1 introduced directional looting for some things.
*/
lootmon:
if (c != 'y' && mon_beside(u.ux, u.uy)) {
if (!get_adjacent_loc("Loot in what direction?",
"Invalid loot location", u.ux, u.uy, &cc))
@@ -2883,20 +2902,27 @@ tipcontainer(box)
struct obj *box; /* or bag */
{
xchar ox = u.ux, oy = u.uy; /* #tip only works at hero's location */
boolean empty_it = FALSE,
/* Shop handling: can't rely on the container's own unpaid
or no_charge status because contents might differ with it.
A carried container's contents will be flagged as unpaid
or not, as appropriate, and need no special handling here.
Items owned by the hero get sold to the shop without
confirmation as with other uncontrolled drops. A floor
container's contents will be marked no_charge if owned by
hero, otherwise they're owned by the shop. By passing
the contents through shop billing, they end up getting
treated the same as in the carried case. We do so one
item at a time instead of doing whole container at once
to reduce the chance of exhausting shk's billing capacity. */
maybeshopgoods = !carried(box) && costly_spot(ox, oy);
boolean empty_it = FALSE, maybeshopgoods;
/* box is either held or on floor at hero's spot; no need to check for
nesting; when held, we need to update its location to match hero's;
for floor, the coordinate updating is redundant */
if (get_obj_location(box, &ox, &oy, 0))
box->ox = ox, box->oy = oy;
/* Shop handling: can't rely on the container's own unpaid
or no_charge status because contents might differ with it.
A carried container's contents will be flagged as unpaid
or not, as appropriate, and need no special handling here.
Items owned by the hero get sold to the shop without
confirmation as with other uncontrolled drops. A floor
container's contents will be marked no_charge if owned by
hero, otherwise they're owned by the shop. By passing
the contents through shop billing, they end up getting
treated the same as in the carried case. We do so one
item at a time instead of doing whole container at once
to reduce the chance of exhausting shk's billing capacity. */
maybeshopgoods = !carried(box) && costly_spot(box->ox, box->oy);
/* caveat: this assumes that cknown, lknown, olocked, and otrapped
fields haven't been overloaded to mean something special for the
@@ -2959,7 +2985,7 @@ struct obj *box; /* or bag */
if (empty_it) {
struct obj *otmp, *nobj;
boolean verbose = FALSE, highdrop = !can_reach_floor(TRUE),
boolean terse, highdrop = !can_reach_floor(TRUE),
altarizing = IS_ALTAR(levl[ox][oy].typ),
cursed_mbag = (Is_mbag(box) && box->cursed);
int held = carried(box);
@@ -2967,20 +2993,27 @@ struct obj *box; /* or bag */
if (u.uswallow)
highdrop = altarizing = FALSE;
terse = !(highdrop || altarizing || costly_spot(box->ox, box->oy));
box->cknown = 1;
/* Terse formatting is
* "Objects spill out: obj1, obj2, obj3, ..., objN."
* If any other messages intervene between objects, we revert to
* "ObjK drops to the floor.", "ObjL drops to the floor.", &c.
*/
pline("%s out%c",
box->cobj->nobj ? "Objects spill" : "An object spills",
!(highdrop || altarizing) ? ':' : '.');
terse ? ':' : '.');
for (otmp = box->cobj; otmp; otmp = nobj) {
nobj = otmp->nobj;
obj_extract_self(otmp);
otmp->ox = box->ox, otmp->oy = box->oy;
if (box->otyp == ICE_BOX) {
removed_from_icebox(otmp); /* resume rotting for corpse */
} else if (cursed_mbag && !rn2(13)) {
loss += mbag_item_gone(held, otmp);
/* abbreviated drop format is no longer appropriate */
verbose = TRUE;
terse = FALSE;
continue;
}
@@ -2993,14 +3026,18 @@ struct obj *box; /* or bag */
/* might break or fall down stairs; handles altars itself */
hitfloor(otmp);
} else {
if (altarizing)
if (altarizing) {
doaltarobj(otmp);
else if (verbose)
} else if (!terse) {
pline("%s %s to the %s.", Doname2(otmp),
otense(otmp, "drop"), surface(ox, oy));
else
} else {
pline("%s%c", doname(otmp), nobj ? ',' : '.');
iflags.last_msg = PLNMSG_OBJNAM_ONLY;
}
dropy(otmp);
if (iflags.last_msg != PLNMSG_OBJNAM_ONLY)
terse = FALSE; /* terse formatting has been interrupted */
}
if (maybeshopgoods)
iflags.suppress_price--; /* reset */

View File

@@ -2130,9 +2130,10 @@ boolean unpaid_only;
return price;
}
/* count amount of gold inside container 'obj' and any nested containers */
long
contained_gold(obj)
register struct obj *obj;
struct obj *obj;
{
register struct obj *otmp;
register long value = 0L;
@@ -2867,12 +2868,12 @@ xchar x, y;
boolean isgold = (obj->oclass == COIN_CLASS);
boolean only_partially_your_contents = FALSE;
if (!*u.ushops) /* do cheapest exclusion test first */
return;
if (!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp))
return;
if (!costly_spot(x, y))
return;
if (!*u.ushops)
return;
if (obj->unpaid && !container && !isgold) {
sub_one_frombill(obj, shkp);

View File

@@ -43,7 +43,7 @@ STATIC_DCL int NDECL(throwspell);
STATIC_DCL void NDECL(cast_protection);
STATIC_DCL void FDECL(spell_backfire, (int));
STATIC_DCL const char *FDECL(spelltypemnemonic, (int));
STATIC_DCL boolean FDECL(spell_hurtle_step, (genericptr_t, int, int));
STATIC_DCL boolean FDECL(spell_aim_step, (genericptr_t, int, int));
/* The roles[] table lists the role-specific values for tuning
* percent_success().
@@ -1181,12 +1181,14 @@ boolean atme;
return 1;
}
/*ARGSUSED*/
STATIC_OVL boolean
spell_hurtle_step(arg, x, y)
genericptr_t arg;
spell_aim_step(arg, x, y)
genericptr_t arg UNUSED;
int x, y;
{
if (!isok(x,y)) return FALSE;
if (!isok(x,y))
return FALSE;
if (!ZAP_POS(levl[x][y].typ)
&& !(IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & D_ISOPEN)))
return FALSE;
@@ -1233,7 +1235,7 @@ throwspell()
uc.x = u.ux;
uc.y = u.uy;
walk_path(&uc, &cc, spell_hurtle_step, NULL);
walk_path(&uc, &cc, spell_aim_step, (genericptr_t) 0);
u.dx = cc.x;
u.dy = cc.y;

View File

@@ -31,9 +31,11 @@ all: $(VARDAT) spec_levs quest_levs dungeon
(cd ../util ; $(MAKE) tile2bmp)
x11tiles: ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \
../win/share/other.txt
../win/share/other.txt \
../win/share/monsters.txt
../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \
../win/share/other.txt
../win/share/other.txt \
-grayscale ../win/share/monsters.txt
beostiles: ../util/tile2beos ../win/share/monsters.txt \
../win/share/objects.txt \

View File

@@ -177,7 +177,7 @@ char **argv;
header.per_row = TILES_PER_ROW;
if (argc == 1) {
Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...]\n", argv[0]);
Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...] [-grayscale txt_fileN]\n", argv[0]);
exit(1);
}
@@ -190,8 +190,15 @@ char **argv;
/* don't leave garbage at end of partial row */
(void) memset((genericptr_t) tile_bytes, 0, sizeof(tile_bytes));
for (i = 1; i < argc; i++)
for (i = 1; i < argc; i++) {
if (!strncmp(argv[i], "-grayscale", 10)) {
set_grayscale(TRUE);
if (i < (argc - 1)) i++;
} else {
set_grayscale(FALSE);
}
process_file(argv[i]);
}
Fprintf(stderr, "Total tiles: %ld\n", header.ntiles);
/* round size up to the end of the row */

View File

@@ -7108,7 +7108,7 @@ Z = (195, 195, 195)
..KKAKKAAKKKOAA.
.JKKKAAAKKKOKA..
.KKKKKKKKKLOAA..
.KOOLKKKKKOKA..K
.KOOLKKKKKOKA...
..JKOOKKKKOAA...
....JKLOOOKA....
......JJKKAA....

View File

@@ -57,8 +57,10 @@ boolean read_text_tile(pixel[TILE_Y][TILE_X]);
boolean write_text_tile(pixel[TILE_Y][TILE_X]);
writes tile
There are two additional shared routines provided for writers:
There are some additional shared routines provided for writers:
void set_grayscale(boolean g);
do grayscale color substitutions when reading the tile text file
void init_colormap();
initialize the output colormap from the input one
must be called before opening output file as colormap is part of header

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 tile.h $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */
/* NetHack 3.6 tile.h $NHDT-Date: 1466687973 2016/06/23 13:19:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ */
typedef unsigned char pixval;
typedef struct pixel_s {
@@ -35,6 +35,7 @@ extern boolean FDECL(read_text_tile, (pixel(*) [TILE_X]));
extern boolean FDECL(write_text_tile, (pixel(*) [TILE_X]));
extern int NDECL(fclose_text_file);
extern void FDECL(set_grayscale, (int));
extern void NDECL(init_colormap);
extern void NDECL(merge_colormap);

View File

@@ -237,6 +237,7 @@ char *argv[];
}
initflag = 1;
}
set_grayscale(pass == 3);
/* printf("Colormap initialized\n"); */
while (read_text_tile(tilepixels)) {
build_bmptile(tilepixels);
@@ -327,11 +328,6 @@ BITMAPINFOHEADER *pbmih;
pbmih->biClrImportant = (DWORD) 0;
}
static int graymappings[] = {
/* . A B C D E F G H I J K L M N O P */
0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14
};
static void
build_bmptile(pixels)
pixel (*pixels)[TILE_X];
@@ -351,14 +347,6 @@ pixel (*pixels)[TILE_X];
Fprintf(stderr, "color not in colormap!\n");
y = (MAX_Y - 1) - (cur_y + yoffset);
apply_color = cur_color;
if (pass == 3) {
/* map to shades of gray */
if (cur_color > (SIZE(graymappings) - 1))
Fprintf(stderr, "Gray mapping issue %d %d.\n", cur_color,
SIZE(graymappings) - 1);
else
apply_color = graymappings[cur_color];
}
#if BITCOUNT == 4
x = (cur_x / 2) + xoffset;
bmp.packtile[y][x] = cur_x % 2

View File

@@ -21,7 +21,7 @@ extern void FDECL(exit, (int));
#endif
#endif
#if defined(MSDOS) || defined(WIN32)
#if defined(MSDOS) || defined(WIN32) || defined(X11_GRAPHICS)
#define STATUES_LOOK_LIKE_MONSTERS
#endif

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 tiletext.c $NHDT-Date: 1454464783 2016/02/03 01:59:43 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ */
/* NetHack 3.6 tiletext.c $NHDT-Date: 1466687974 2016/06/23 13:19:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.14 $ */
/* NetHack may be freely redistributed. See license for details. */
#include "config.h"
@@ -37,6 +37,20 @@ static void FDECL(write_txttile, (FILE *, pixel (*)[TILE_X]));
"%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.] = " \
"(%d, %d, %d) "
static int grayscale = 0;
/* grayscale color mapping */
static const int graymappings[] = {
/* . A B C D E F G H I J K L M N O P */
0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14
};
void
set_grayscale(g)
int g;
{
grayscale = g;
}
static void
read_text_colormap(txtfile)
FILE *txtfile;
@@ -135,6 +149,13 @@ pixel (*pixels)[TILE_X];
return FALSE;
}
k = color_index[(int) c[0]];
if (grayscale) {
if (k > (SIZE(graymappings) - 1))
Fprintf(stderr, "Gray mapping issue %d > %d.\n", k,
SIZE(graymappings) - 1);
else
k = graymappings[k];
}
if (k == -1)
Fprintf(stderr, "color %c not in colormap!\n", c[0]);
else {

View File

@@ -8,7 +8,6 @@
#include "tcap.h"
#include "wintty.h"
#include <ctype.h>
#ifndef C /* this matches src/cmd.c */
#define C(c) (0x1f & (c))
@@ -48,8 +47,7 @@ tty_doprev_message()
do {
morc = 0;
if (cw->maxcol == cw->maxrow) {
ttyDisplay->dismiss_more =
C('p'); /* <ctrl/P> allowed at --More-- */
ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */
redotoplin(toplines);
cw->maxcol--;
if (cw->maxcol < 0)
@@ -57,8 +55,7 @@ tty_doprev_message()
if (!cw->data[cw->maxcol])
cw->maxcol = cw->maxrow;
} else if (cw->maxcol == (cw->maxrow - 1)) {
ttyDisplay->dismiss_more =
C('p'); /* <ctrl/P> allowed at --More-- */
ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */
redotoplin(cw->data[cw->maxcol]);
cw->maxcol--;
if (cw->maxcol < 0)
@@ -130,6 +127,7 @@ redotoplin(str)
const char *str;
{
int otoplin = ttyDisplay->toplin;
home();
if (*str & 0x80) {
/* kludge for the / command, the only time we ever want a */
@@ -251,10 +249,11 @@ register const char *bp;
(void) strncpy(toplines, bp, TBUFSZ);
toplines[TBUFSZ - 1] = 0;
for (tl = toplines; n0 >= CO;) {
for (tl = toplines; n0 >= CO; ) {
otl = tl;
for (tl += CO - 1; tl != otl && !isspace(*tl); --tl)
;
for (tl += CO - 1; tl != otl; --tl)
if (*tl == ' ')
break;
if (tl == otl) {
/* Eek! A huge token. Try splitting after it. */
tl = index(otl, ' ');
@@ -299,7 +298,7 @@ char c;
break;
default:
if (ttyDisplay->curx == CO - 1)
topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */
topl_putsym('\n'); /* 1 <= curx < CO; avoid CO */
#ifdef WIN32CON
(void) putchar(c);
#endif

View File

@@ -2443,22 +2443,27 @@ compress_str(str)
const char *str;
{
static char cbuf[BUFSZ];
/* compress in case line too long */
if ((int) strlen(str) >= CO) {
register const char *bp0 = str;
register char *bp1 = cbuf;
/* compress out consecutive spaces if line is too long;
topline wrapping converts space at wrap point into newline,
we reverse that here */
if ((int) strlen(str) >= CO || index(str, '\n')) {
register const char *bp0 = str;
char c, nxtc, *bp1 = cbuf, *endbp1 = &cbuf[sizeof cbuf - 1];
cbuf[0] = cbuf[sizeof cbuf - 1] = '\0'; /* superfluous */
nxtc = (*bp0 == '\n') ? ' ' : *bp0;
do {
#ifdef CLIPPING
if (*bp0 != ' ' || bp0[1] != ' ')
#else
if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
#endif
*bp1++ = *bp0;
} while (*bp0++);
} else
return str;
return cbuf;
c = nxtc;
nxtc = bp0[1];
if (nxtc == '\n')
nxtc = ' ';
if (c != ' ' || nxtc != ' ')
*bp1++ = c;
} while (*bp0++ && bp1 < endbp1);
str = cbuf;
}
return str;
}
void
@@ -2601,7 +2606,7 @@ const char *str;
}
if (cw->data[cw->cury])
free((genericptr_t) cw->data[cw->cury]);
n0 = strlen(str) + 1;
n0 = (long) strlen(str) + 1L;
ob = cw->data[cw->cury] = (char *) alloc((unsigned) n0 + 1);
*ob++ = (char) (attr + 1); /* avoid nuls, for convenience */
Strcpy(ob, str);