From 34b45a2c101feff1d5a37c9ed89a16a3efaf970d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 4 Jan 2016 18:05:16 +0200 Subject: [PATCH 01/86] Add an alternative paniclog format as compile-time option --- include/config.h | 4 ++++ src/files.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/include/config.h b/include/config.h index 141a6845a..3392e6407 100644 --- a/include/config.h +++ b/include/config.h @@ -206,6 +206,10 @@ #define NEWS "news" /* the file containing the latest hack news */ #define PANICLOG "paniclog" /* log of panic and impossible events */ +/* alternative paniclog format, better suited for public servers with + many players, as it saves the player name and the game start time */ +/* #define PANICLOG_FMT2 */ + /* * PERSMAX, POINTSMIN, ENTRYMAX, PERS_IS_UID: * These control the contents of 'record', the high-scores file. diff --git a/src/files.c b/src/files.c index 059090b1f..8836b2b90 100644 --- a/src/files.c +++ b/src/files.c @@ -3120,6 +3120,11 @@ const char *reason; /* explanation */ program_state.in_paniclog = 1; lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX); if (lfile) { +#ifdef PANICLOG_FMT2 + (void) fprintf(lfile, "%ld %s: %s %s\n", + ubirthday, (plname ? plname : "(none)"), + type, reason); +#else time_t now = getnow(); int uid = getuid(); char playmode = wizard ? 'D' : discover ? 'X' : '-'; @@ -3127,6 +3132,7 @@ const char *reason; /* explanation */ (void) fprintf(lfile, "%s %08ld %06ld %d %c: %s %s\n", version_string(buf), yyyymmdd(now), hhmmss(now), uid, playmode, type, reason); +#endif /* !PANICLOG_FMT2 */ (void) fclose(lfile); } program_state.in_paniclog = 0; From 89e4d5e9faa5aa420631185d019293592897d727 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 4 Jan 2016 19:52:34 +0200 Subject: [PATCH 02/86] Add SIMPLE_MAIL compile-time option for public servers --- include/unixconf.h | 9 ++++++ src/mail.c | 69 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/include/unixconf.h b/include/unixconf.h index bc6984eec..751895ba9 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -191,7 +191,16 @@ #endif #endif +/* If SIMPLE_MAIL is defined, the mail spool file format is + "sender:message", one mail per line, and mails are + read within game, from demon-delivered mail scrolls */ +/* #define SIMPLE_MAIL */ + +#ifndef MAILCKFREQ +/* How often mail spool file is checked for new messages, in turns */ #define MAILCKFREQ 50 +#endif + #endif /* MAIL */ /* diff --git a/src/mail.c b/src/mail.c index fb9c07c50..ec31393a4 100644 --- a/src/mail.c +++ b/src/mail.c @@ -5,6 +5,10 @@ #include "hack.h" #ifdef MAIL +#ifdef SIMPLE_MAIL +# include +# include +#endif /* SIMPLE_MAIL */ #include "mail.h" /* @@ -498,6 +502,64 @@ ckmailstatus() } } +#ifdef SIMPLE_MAIL +void +read_simplemail() +{ + FILE* mb = fopen(mailbox, "r"); + char curline[102], *msg; + boolean seen_one_already = FALSE; + struct flock fl = { 0 }; + + fl.l_type = F_RDLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + + if (!mb) + goto bail; + + /* Allow this call to block. */ + if (fcntl (fileno (mb), F_SETLKW, &fl) == -1) + goto bail; + + errno = 0; + while (fgets(curline, 102, mb) != NULL) { + fl.l_type = F_UNLCK; + fcntl (fileno(mb), F_UNLCK, &fl); + + pline("There is a%s message on this scroll.", + seen_one_already ? "nother" : ""); + + msg = strchr(curline, ':'); + + if (!msg) + goto bail; + + *msg = '\0'; + msg++; + + pline("This message is from '%s'.", curline); + + msg[strlen(msg) - 1] = '\0'; /* kill newline */ + pline ("It reads: \"%s\".", msg); + + seen_one_already = TRUE; + errno = 0; + + fl.l_type = F_RDLCK; + fcntl(fileno(mb), F_SETLKW, &fl); + } + + fl.l_type = F_UNLCK; + fcntl(fileno(mb), F_UNLCK, &fl); + fclose(mb); + unlink(mailbox); +bail: + pline("It appears to be all gibberish."); /* bail out _professionally_ */ +} +#endif /* SIMPLE_MAIL */ + /*ARGSUSED*/ void readmail(otmp) @@ -505,7 +567,12 @@ struct obj *otmp UNUSED; { #ifdef DEF_MAILREADER /* This implies that UNIX is defined */ register const char *mr = 0; - +#endif /* DEF_MAILREADER */ +#ifdef SIMPLE_MAIL + read_simplemail(); + return; +#endif /* SIMPLE_MAIL */ +#ifdef DEF_MAILREADER /* This implies that UNIX is defined */ display_nhwindow(WIN_MESSAGE, FALSE); if (!(mr = nh_getenv("MAILREADER"))) mr = DEF_MAILREADER; From e9b0fa23d2f78db23444c3749171d53ca788ff18 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 4 Jan 2016 23:04:56 +0200 Subject: [PATCH 03/86] Add server admin messaging functionality It's occasionally important for public servers to notify all the players. Sending a mail is not reliable, as not everyone wants to break conduct, or have mail on. This adds a compile-time defined filename, which NetHack will monitor. The contents of the file are in the same format as SIMPLE_MAIL: "sender:message" on one line. --- include/extern.h | 1 + include/unixconf.h | 14 +++++- src/allmain.c | 1 + src/mail.c | 108 ++++++++++++++++++++++++++++++++------------- 4 files changed, 93 insertions(+), 31 deletions(-) diff --git a/include/extern.h b/include/extern.h index 3bba9fe1d..537c58a06 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1062,6 +1062,7 @@ E void FDECL(nocmov, (int x, int y)); #ifdef UNIX E void NDECL(getmailstatus); #endif +E void NDECL(ck_server_admin_msg); E void NDECL(ckmailstatus); E void FDECL(readmail, (struct obj *)); #endif /* MAIL */ diff --git a/include/unixconf.h b/include/unixconf.h index 751895ba9..236994bce 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -193,7 +193,9 @@ /* If SIMPLE_MAIL is defined, the mail spool file format is "sender:message", one mail per line, and mails are - read within game, from demon-delivered mail scrolls */ + read within game, from demon-delivered mail scrolls. + The mail spool file will be deleted once the player + has read the message. */ /* #define SIMPLE_MAIL */ #ifndef MAILCKFREQ @@ -203,6 +205,16 @@ #endif /* MAIL */ +/* If SERVER_ADMIN_MSG is defined and the file exists, players get + a message from the user defined in the file. The file format + is "sender:message" all in one line. */ +/* #define SERVER_ADMIN_MSG "adminmsg" */ +#ifndef SERVER_ADMIN_MSG_CKFREQ +/* How often admin message file is checked for new messages, in turns */ +#define SERVER_ADMIN_MSG_CKFREQ 25 +#endif + + /* * Some terminals or terminal emulators send two character sequence "ESC c" * when Alt+c is pressed. The altmeta run-time option allows the user to diff --git a/src/allmain.c b/src/allmain.c index 9f4329143..9bc6bdcab 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -455,6 +455,7 @@ boolean resuming; rhack(save_cm); } } else if (multi == 0) { + ck_server_admin_msg(); #ifdef MAIL ckmailstatus(); #endif diff --git a/src/mail.c b/src/mail.c index ec31393a4..552f263d4 100644 --- a/src/mail.c +++ b/src/mail.c @@ -502,35 +502,50 @@ ckmailstatus() } } -#ifdef SIMPLE_MAIL +#if defined(SIMPLE_MAIL) || defined(SERVER_ADMIN_MSG) void -read_simplemail() +read_simplemail(mbox, adminmsg) +char *mbox; +boolean adminmsg; { - FILE* mb = fopen(mailbox, "r"); - char curline[102], *msg; + FILE* mb = fopen(mbox, "r"); + char curline[128], *msg; boolean seen_one_already = FALSE; +#ifdef SIMPLE_MAIL struct flock fl = { 0 }; - - fl.l_type = F_RDLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; +#endif + const char *msgfrom = adminmsg + ? "The voice of %s booms through the caverns:" + : "This message is from '%s'."; if (!mb) goto bail; +#ifdef SIMPLE_MAIL + fl.l_type = F_RDLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + errno = 0; +#endif + /* Allow this call to block. */ - if (fcntl (fileno (mb), F_SETLKW, &fl) == -1) + if (!adminmsg +#ifdef SIMPLE_MAIL + && fcntl (fileno (mb), F_SETLKW, &fl) == -1 +#endif + ) goto bail; - errno = 0; - while (fgets(curline, 102, mb) != NULL) { - fl.l_type = F_UNLCK; - fcntl (fileno(mb), F_UNLCK, &fl); - - pline("There is a%s message on this scroll.", - seen_one_already ? "nother" : ""); - + while (fgets(curline, 128, mb) != NULL) { + if (!adminmsg) { +#ifdef SIMPLE_MAIL + fl.l_type = F_UNLCK; + fcntl (fileno(mb), F_UNLCK, &fl); +#endif + pline("There is a%s message on this scroll.", + seen_one_already ? "nother" : ""); + } msg = strchr(curline, ':'); if (!msg) @@ -538,28 +553,61 @@ read_simplemail() *msg = '\0'; msg++; - - pline("This message is from '%s'.", curline); - msg[strlen(msg) - 1] = '\0'; /* kill newline */ - pline ("It reads: \"%s\".", msg); + + pline(msgfrom, curline); + if (adminmsg) + verbalize(msg); + else + pline("It reads: \"%s\".", msg); seen_one_already = TRUE; +#ifdef SIMPLE_MAIL errno = 0; - - fl.l_type = F_RDLCK; - fcntl(fileno(mb), F_SETLKW, &fl); + if (!adminmsg) { + fl.l_type = F_RDLCK; + fcntl(fileno(mb), F_SETLKW, &fl); + } +#endif } - fl.l_type = F_UNLCK; - fcntl(fileno(mb), F_UNLCK, &fl); +#ifdef SIMPLE_MAIL + if (!adminmsg) { + fl.l_type = F_UNLCK; + fcntl(fileno(mb), F_UNLCK, &fl); + } +#endif fclose(mb); - unlink(mailbox); + if (adminmsg) + display_nhwindow(WIN_MESSAGE, TRUE); + else + unlink(mailbox); + return; bail: - pline("It appears to be all gibberish."); /* bail out _professionally_ */ + /* bail out _professionally_ */ + if (!adminmsg) + pline("It appears to be all gibberish."); } #endif /* SIMPLE_MAIL */ +void +ck_server_admin_msg() +{ +#ifdef SERVER_ADMIN_MSG + static struct stat ost,nst; + static long lastchk = 0; + + if (moves < lastchk + SERVER_ADMIN_MSG_CKFREQ) return; + lastchk = moves; + + if (!stat(SERVER_ADMIN_MSG, &nst)) { + if (nst.st_mtime > ost.st_mtime) + read_simplemail(SERVER_ADMIN_MSG, TRUE); + ost.st_mtime = nst.st_mtime; + } +#endif /* SERVER_ADMIN_MSG */ +} + /*ARGSUSED*/ void readmail(otmp) @@ -569,7 +617,7 @@ struct obj *otmp UNUSED; register const char *mr = 0; #endif /* DEF_MAILREADER */ #ifdef SIMPLE_MAIL - read_simplemail(); + read_simplemail(mailbox, FALSE); return; #endif /* SIMPLE_MAIL */ #ifdef DEF_MAILREADER /* This implies that UNIX is defined */ From 1e0b16c99dcbd228fb467adf1653428107261117 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 4 Jan 2016 23:19:49 +0200 Subject: [PATCH 04/86] Add the compile-time options to fixes-file --- doc/fixes36.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index cc6cf57a7..51f012d18 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -81,6 +81,7 @@ ensure sufficient messages are given to clarify the transition from detected vampire bats to fog clouds in Vlad's tower fix "killing by kicking something weird" when kicking an object causes death guard macros available for mextra fields similar to those for oextra fields +compile-time option for an alternate paniclog format for public server use Platform- and/or Interface-Specific Fixes @@ -115,6 +116,7 @@ reading non-cursed scroll of enchant weapon uncurses welded tin opener if hero has no jumping ability but knows the jumping spell, the #jump command will attempt to cast the spell additional tribute passages for The Colour of Magic, Snuff, and Raising Steam +compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use Platform- and/or Interface-Specific New Features From e8e1673df72067f815b8bf2d46c72e96c63bcbca Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 4 Jan 2016 16:51:24 -0800 Subject: [PATCH 05/86] build fix for ck_server_admin_msg() ck_server_admin_msg() is only available for '#if (UNIX && MAIL)' but moveloop() tried to call it unconditionally. Call if from the UNIX edition of ckmailstatus() instead. --- include/extern.h | 4 ++-- src/allmain.c | 3 +-- src/mail.c | 4 +++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/extern.h b/include/extern.h index 537c58a06..49ed2ec6a 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1451174855 2015/12/27 00:07:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.526 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1451955077 2016/01/05 00:51:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.530 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1061,8 +1061,8 @@ E void FDECL(nocmov, (int x, int y)); #ifdef MAIL #ifdef UNIX E void NDECL(getmailstatus); -#endif E void NDECL(ck_server_admin_msg); +#endif E void NDECL(ckmailstatus); E void FDECL(readmail, (struct obj *)); #endif /* MAIL */ diff --git a/src/allmain.c b/src/allmain.c index 9bc6bdcab..737dcf0d5 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 allmain.c $NHDT-Date: 1451344214 2015/12/28 23:10:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.68 $ */ +/* NetHack 3.6 allmain.c $NHDT-Date: 1451955079 2016/01/05 00:51:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -455,7 +455,6 @@ boolean resuming; rhack(save_cm); } } else if (multi == 0) { - ck_server_admin_msg(); #ifdef MAIL ckmailstatus(); #endif diff --git a/src/mail.c b/src/mail.c index 552f263d4..7c3546835 100644 --- a/src/mail.c +++ b/src/mail.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mail.c $NHDT-Date: 1450261364 2015/12/16 10:22:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.22 $ */ +/* NetHack 3.6 mail.c $NHDT-Date: 1451955080 2016/01/05 00:51:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.25 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -470,6 +470,8 @@ struct obj *otmp UNUSED; void ckmailstatus() { + ck_server_admin_msg(); + if (!mailbox || u.uswallow || !flags.biff #ifdef MAILCKFREQ || moves < laststattime + MAILCKFREQ From a037c6fc28146a26c6988dc6f64288b204e79ed4 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 4 Jan 2016 17:19:56 -0800 Subject: [PATCH 06/86] tribute: The Light Fantastic --- dat/tribute | 239 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 223 insertions(+), 16 deletions(-) diff --git a/dat/tribute b/dat/tribute index cfe4699cf..37eb2d374 100644 --- a/dat/tribute +++ b/dat/tribute @@ -329,43 +329,246 @@ the most courted and the most cursed. # # # -%title The Light Fantastic (2) +%title The Light Fantastic (12) +# p. 92 (Signet edition) %passage 1 -'Cohen is my name, boy' Belthan's hands stopped moving. -'Cohen?' she said, 'Cohen the Barbarian?' +'Cohen ish my name, boy.' Bethan's hands stopped moving. + +'Cohen?' she said. 'Cohen the Barbarian?' + 'The very shame.' -'Hang on, hang on,' said Rincewind, 'Cohen's a great big chap, neck like a + +'Hang on, hang on,' said Rincewind. 'Cohen's a great big chap, neck like a bull, got chest muscles like a sack of footballs. I mean, he's the Disc's greatest warrior, a legend in his own lifetime. I remember my grandad -telling me he saw him ... my grandad telling me he ... my grandad ...' +telling me he saw him... my grandad telling me he... my grandad...' + He faltered under the gimlit gaze. -'Oh,' he said, 'Oh. Of course, Sorry.' -'Yesh,' said Cohen, and sighed, 'Thatsh right boy, I'm a lifetime in my own -legend.' + +'Oh,' he said. 'Oh. Of course. Sorry.' + +'Yesh,' said Cohen, and sighed. 'That's right boy. I'm a lifetime in my +own legend.' [The Light Fantastic, by Terry Pratchett] %e passage 1 +# p. 113 (Twoflower is teaching the Riders how to play bridge; +# in /The Light Fantastic/, Death's dialog uses quotation marks +# and full uppercase rather than the small capital letters used in +# the other books) %passage 2 -Death sat at one side of a black baize table in the entre of the room, +Death sat at one side of a black baize table in the centre of the room, arguing with Famine, War and Pestilence. Twoflower was the only one to look up and notice Rincewind. + 'Hey, how did you get here?' he said. -'Well, some say that the creator took a handful - oh, I see, well, it's -hard to explain but I -' + +'Well, some say that the creator took a handful--oh, I see, well, it's +hard to explain but I--' + 'Have you got the Luggage?' + The wooden box pushed past Rincewind and settled down in front of its owner, who opened its lid and rummaged around inside until he came up with a small, leatherbound book which he handed to War, who was hammering the table with a mailed fist. -'It's "Nosehinger on the Laws of Contract",' he said. 'It's quite good, -there's a lot in it about double finessing and how to -' -Death snatched the book with a bony hand and flipped through the pages, + +'It's "Nosehinger on the Laws of Contract",' he said. 'It's quite good, +there's a lot in it about double finessing and how to--' + +Death snatched the book with a bony hand and flipped through the pages, quite oblivious to the presence of the two men. -'RIGHT,' he said, 'PESTILENCE, OPEN ANOTHER PACK OF CARDS. I'M GOING TO GET -TO THE BOTTOM OF THIS IF IT KILLS ME. FIGURATIVELY SPEAKING OF COURSE.' + +'RIGHT,' he said, 'PESTILENCE, OPEN ANOTHER PACK OF CARDS. I'M GOING TO +GET TO THE BOTTOM OF THIS IF IT KILLS ME. FIGURATIVELY SPEAKING OF COURSE.' [The Light Fantastic, by Terry Pratchett] %e passage 2 +# p. 7 (passage starts mid-paragraph; the too-long-to-answer question is +# "Why have Rincewind and Twoflower fallen off the Disc's rim?", +# alluding to the conclusion of /The Colour of Magic/; +# in /Sourcery/ and /Interesting Times/ and probably others, the +# famous philosohper's name is spelled "Ly Tin Wheedle") +%passage 3 +[...] such questions take time and could be more trouble than they are +worth. For example, it is said that someone at a party once asked the +famous philosopher Ly Tin Weedle "Why are you here?" and the reply took +three years. + + [The Light Fantastic, by Terry Pratchett] +%e passage +# p. 8 ('libraries': plural is accurate) +%passage 4 +The only furnishing in the room was a lectern of dark wood, carved into the +shape of a bird--well, to be frank, into the shape of a winged thing it is +probably best not to examine too closely--and on the lectern, fastened to +it by a heavy chain covered in padlocks, was a book. + +A large, but not particularly impressive, book. Other books in the +University's libraries had covers inlaid with rare jewels and fascinating +wood, or bound with dragon skin. This one was just a rather tatty leather. +It looked the sort of book described in library catalogues as "slightly +foxed," although it would be more honest to admit that it looked as though +it had been badgered, wolved and possibly beared as well. + + [The Light Fantastic, by Terry Pratchett] +%e passage +# pp. 41-42 +%passage 5 +The barbarian chieftain said: "What then are the greatest things that a +man may find in life?" This is the sort of thing you're supposed to say to +maintain steppecred in barbarian circles. + +The man on his right thoughtfully drank his cocktail of mare's milk and +snowcat blood, and spoke thus: "The crisp horizon of the steppe, the wind +in your hair, a fresh horse under you." + +The man on his left said: "The cry of the white eagle in the heights, the +fall of snow in the forest, a true arrow in your bow." + +The chieftain nodded and said: "Surely it is the sight of your enemy +slain, the humiliation of his tribe and the lamentation of his women." + +There was a general murmur of whiskery approval at this outrageous display. + +Then the chieftain turned respectfully to his guest, a small figure +carefully warming his chilblains by the fire, and said: "But our guest, +whose name is legend, must tell us truly: what is it that a man may call +the greatest things in life?" + +The guest paused in the middle of another unsuccessful attempt to light up. + +"What shay?" he said, toothlessly. + +"I said: what is it that a man may call the greatest things in life?" + +The warriors leaned closer. This should be worth hearing. + +The guest thought long and hard and then said, with deliberation: "Hot +water, good dentishtry and shoft lavatory paper." + + [The Light Fantastic, by Terry Pratchett] +%e passage +# p. 48 (Hanzel and Gretel, obviously...) +%passage 6 +"Have a bit more table," said Rincewind. + +"No thanks, I don't like marzipan," said Twoflower. "Anyway, I'm sure it's +not right to eat other people's furniture." + +"Don't worry," said Swires. "The old witch hasn't been seen for years. +They say she was done up good and proper by a couple of young tearaways." + +"Kids of today," said Rincewind. + +"I blame the parents," said Twoflower. + + [The Light Fantastic, by Terry Pratchett] +%e passage +# p. 103 +%passage 7 +It is a well known fact that warriors and wizards do not get along, because +one side considers the other side to be a collection of bloodthirsty idiots +who can't walk and think at the same time, while the other side is naturally +suspicious of a body of men who mumble a lot and wear long dresses. Oh, say +the wizards, if we're going to be like that, then, what about all those +studded collars and oiled muscles down at the Young Men's Pagan Association? +To which the heroes reply, that's a pretty good allegation coming from a +bunch of wimpsoes who won't go near a woman on account, can you believe it, +of their mystical power being sort of drained out. Right, say the wizards, +that just about does it, you and your leather posing pouches. Oh yeah, say +the heroes, why don't you... + +And so on. This sort of thing has been going on for centuries, and caused +a number of major battles which have left large tracts of land uninhabitable +because of magical harmonics. + + [The Light Fantastic, by Terry Pratchett] +%e passage +# p. 128 +%passage 8 +"He'sh mad?" + +"Sort of mad. But mad with lots of money." + +"Ah, then he can't be mad. I've been around; if a man hash lotsh of money +he'sh just ecshentric." + + [The Light Fantastic, by Terry Pratchett] +%e passage +# p. 182 (Cohen is now wearing dentures with teeth made from diamonds) +%passage 9 +Cohen tapped him on the shoulder. The man looked around irritably. + +"What do you want, grandad?" he snarled. + +Cohen paused until he had the man's full attention, and then he smiled. It +was a slow, lazy smile, unveiling about 300 carats of mouth jewelry that +seemed to light up the room. + +"I will count to three," he said, in a friendly tone of voice. "One, Two." +His bony knee came up in the man's groin with a satisfyingly meaty noise, +and he half-turned to bring the full force of an elbow into the kidneys as +the leader collapsed around his private universe of pain. + +"Three," to told the ball of agony on the floor. Cohen had heard of +fighting fair, and had long ago decided he wanted no part of it. + + [The Light Fantastic, by Terry Pratchett] +%e passage +# pp. 193-194 (this passage is the data.base quote for shopkeeper) +%passage 10 +There have been three general theories put forward to explain the +phenomenon of the wandering shops, or as they are generically known, +/tabernae vagantes/. + +The first postulates that many thousands of years ago there evolved +somewhere in the multiverse a race whose single talent was to buy cheap +and sell dear. Soon they controlled a vast galactic empire or, as they put +it, Emporium, and the more advanced members of the species found a way to +equip their very shops with unique propulsion units that could break the +dark walls of space itself and open up vast new markets. And long after +the worlds of the Emporium perished in the heat death of their particular +universe, after one last defiant fire sale, the wandering starshops still +ply their trade, eating their way through the pages of space-time like a +worm through a three-volume novel. + +The second is that they are the creation of a sympathetic Fate, charged +with the role of supplying exactly the right thing at the right time. + +The third is that they are simply a very clever way of getting around the +various Sunday Closing acts. + +All these theories, diverse as they are, have two things in common. They +explain the observed facts, and they are completely and utterly wrong. + + [The Light Fantastic, by Terry Pratchett] +%e passage +# p. 205 +%passage 11 +"Where to they all come from?" said Twoflower, as they fled yet another mob. + +"Inside every sane person there's a madman struggling to get out," said the +shopkeeper, "That's what I've always thought. No one goes mad quicker than +a totally sane person." + + [The Light Fantastic, by Terry Pratchett] +%e passage +# pp. 229-230 ('grey': British spelling is accurate) +%passage 12 +Trymon was looking at him. /Something/ was looking at him. And still the +others hadn't noticed. Could he even explain it? Trymon looked the same +as he had always done, except for the eyes, and a slight sheen to his skin. + +Rincewind stared, and knew that there were far worse things than Evil. All +the demons in Hell would torture your very soul, but that was precisely +because they value souls very highly; evil would always try to steal the +universe, but at least it considered the universe worth stealing. But the +grey world behind those empty eyes would trample and destroy without even +according its victims the dignity of hatred. It wouldn't even notice them. + + [The Light Fantastic, by Terry Pratchett] +%e passage %e title # # @@ -6046,6 +6249,10 @@ SHALL WE GO? # p. 251 %passage 13 I HAVE COME FOR THEE. +# The Light Fantastic, p. 52 (Signet edition; quote has quotation marks but +# including them here wouldn't fit with the rest) +%passage 14 +DARK IN HERE, ISN'T IT? %e title %e section # From 366043f7148564a908e55eb84902ee9fcdabbff1 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 4 Jan 2016 17:30:05 -0800 Subject: [PATCH 07/86] tribute catch-up --- doc/fixes36.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 51f012d18..0ab9f3a43 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -115,7 +115,8 @@ wizard mode #wizintrinsic reading non-cursed scroll of enchant weapon uncurses welded tin opener if hero has no jumping ability but knows the jumping spell, the #jump command will attempt to cast the spell -additional tribute passages for The Colour of Magic, Snuff, and Raising Steam +additional tribute passages for The Colour of Magic, The Light Fantastic, + Snuff, and Raising Steam compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use From 5eb9b0827cb9ce7d6d531054f621f65c5d2fb04f Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 4 Jan 2016 21:52:32 -0500 Subject: [PATCH 08/86] Deaf bits for vault --- src/vault.c | 88 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 22 deletions(-) diff --git a/src/vault.c b/src/vault.c index 5b73dadc5..3d40f990b 100644 --- a/src/vault.c +++ b/src/vault.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vault.c $NHDT-Date: 1446078792 2015/10/29 00:33:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.39 $ */ +/* NetHack 3.6 vault.c $NHDT-Date: 1451962301 2016/01/05 02:51:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.40 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -342,7 +342,7 @@ invault() newsym(guard->mx, guard->my); if (u.uswallow) { /* can't interrogate hero, don't interrogate engulfer */ - verbalize("What's going on here?"); + if (!Deaf) verbalize("What's going on here?"); if (gsensed) pline_The("other presence vanishes."); mongone(guard); @@ -351,8 +351,8 @@ invault() if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected) { if (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance != GOLD_PIECE) - verbalize("Hey! Who left that %s in here?", - mimic_obj_name(&youmonst)); + if (!Deaf) verbalize("Hey! Who left that %s in here?", + mimic_obj_name(&youmonst)); /* You're mimicking some object or you're hidden. */ pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); @@ -362,7 +362,10 @@ invault() /* [we ought to record whether this this message has already been given in order to vary it upon repeat visits, but discarding the monster and its egd data renders that hard] */ - verbalize("I'll be back when you're ready to speak to me!"); + if (Deaf) + pline("%s huffs and turns to leave.", noit_Monnam(guard)); + else + verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } @@ -374,7 +377,8 @@ invault() } trycount = 5; do { - getlin("\"Hello stranger, who are you?\" -", buf); + getlin(Deaf ? "You are required to sign in with your name. -" : + "\"Hello stranger, who are you?\" -", buf); (void) mungspaces(buf); } while (!letter(buf[0]) && --trycount > 0); @@ -387,12 +391,22 @@ invault() if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") || !strcmpi(buf, "Creosote")) { if (!mvitals[PM_CROESUS].died) { - verbalize( + if (Deaf) { + if (!Blind) pline("%s waves goodbye.", noit_Monnam(guard)); + } else { + verbalize( "Oh, yes, of course. Sorry to have disturbed you."); + } mongone(guard); } else { setmangry(guard); - verbalize("Back from the dead, are you? I'll remedy that!"); + if (Deaf) { + if (!Blind) + pline("%s mouths something and looks very angry!", + noit_Monnam(guard)); + } else { + verbalize("Back from the dead, are you? I'll remedy that!"); + } /* don't want guard to waste next turn wielding a weapon */ if (!MON_WEP(guard)) { guard->weapon_check = NEED_HTH_WEAPON; @@ -401,18 +415,37 @@ invault() } return; } - verbalize("I don't know you."); + if (Deaf) + pline("%s doesn't %srecognize you.", noit_Monnam(guard), + (Blind) ? "" : "appear to "); + else + verbalize("I don't know you."); umoney = money_cnt(invent); - if (Deaf) { - ; - } else if (!umoney && !hidden_gold()) { - verbalize("Please follow me."); + if (!umoney && !hidden_gold()) { + if (Deaf) + pline("%s stomps%s.", noit_Monnam(guard), + (Blind) ? "" : " and beckons"); + else + verbalize("Please follow me."); } else { - if (!umoney) - verbalize("You have hidden gold."); - verbalize( - "Most likely all your gold was stolen from this vault."); - verbalize("Please drop that gold and follow me."); + if (!umoney) { + if (Deaf) { + if (!Blind) + pline("%s glares at you%s.", noit_Monnam(guard), + invent ? "r stuff" : ""); + } else { + verbalize("You have hidden gold."); + } + } + if (Deaf) { + if (!Blind) + pline("%s holds out %s palm and beckons with %s other hand.", + noit_Monnam(guard), mhis(guard), mhis(guard)); + } else { + verbalize( + "Most likely all your gold was stolen from this vault."); + verbalize("Please drop that gold and follow me."); + } } EGD(guard)->gdx = gx; EGD(guard)->gdy = gy; @@ -578,8 +611,9 @@ register struct monst *grd; return -1; /* teleported guard - treat as monster */ if (egrd->witness) { - verbalize("How dare you %s that gold, scoundrel!", - (egrd->witness & GD_EATGOLD) ? "consume" : "destroy"); + if (!Deaf) + verbalize("How dare you %s that gold, scoundrel!", + (egrd->witness & GD_EATGOLD) ? "consume" : "destroy"); egrd->witness = 0; grd->mpeaceful = 0; return -1; @@ -655,12 +689,22 @@ register struct monst *grd; } if (egrd->warncnt < 6) { egrd->warncnt = 6; - if (!Deaf) + if (Deaf) { + if (!Blind) + pline("%s holds out %s palm demandingly!", + noit_Monnam(grd), mhis(grd)); + } else { verbalize("Drop all your gold, scoundrel!"); + } return 0; } else { - if (!Deaf) + if (Deaf) { + if (!Blind) + pline("%s rubs %s hands with enraged delight!", + noit_Monnam(grd), mhis(grd)); + } else { verbalize("So be it, rogue!"); + } grd->mpeaceful = 0; return -1; } From ece4407c4128b7ead9cd3116c2b300c55c610ad6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 5 Jan 2016 07:42:28 +0200 Subject: [PATCH 09/86] Finish splitting wallification into two --- src/mkmaze.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/mkmaze.c b/src/mkmaze.c index 100b0b525..f192a3f3c 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -123,13 +123,9 @@ int wall_there, dx, dy; return spine; } -/* - * Wall cleanup. This function has two purposes: (1) remove walls that - * are totally surrounded by stone - they are redundant. (2) correct - * the types so that they extend and connect to each other. - */ +/* Remove walls totally surrounded by stone */ void -wallification(x1, y1, x2, y2) +wall_cleanup(x1, y1, x2, y2) int x1, y1, x2, y2; { uchar type; @@ -138,9 +134,9 @@ int x1, y1, x2, y2; /* sanity check on incoming variables */ if (x1 < 0 || x2 >= COLNO || x1 > x2 || y1 < 0 || y2 >= ROWNO || y1 > y2) - panic("wallification: bad bounds (%d,%d) to (%d,%d)", x1, y1, x2, y2); + panic("wall_cleanup: bad bounds (%d,%d) to (%d,%d)", x1, y1, x2, y2); - /* Step 1: change walls surrounded by rock to rock. */ + /* change walls surrounded by rock to rock. */ for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) { lev = &levl[x][y]; @@ -153,10 +149,9 @@ int x1, y1, x2, y2; lev->typ = STONE; } } - - fix_wall_spines(x1,y1,x2,y2); } +/* Correct wall types so they extend and connect to each other */ void fix_wall_spines(x1, y1, x2, y2) int x1, y1, x2, y2; @@ -181,11 +176,7 @@ int x1, y1, x2, y2; if (x1<0 || x2>=COLNO || x1>x2 || y1<0 || y2>=ROWNO || y1>y2) panic("wall_extends: bad bounds (%d,%d) to (%d,%d)",x1,y1,x2,y2); - /* - * Step 2: set the correct wall type. We can't combine steps - * 1 and 2 into a single sweep because we depend on knowing if - * the surrounding positions are stone. - */ + /* set the correct wall type. */ for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) { lev = &levl[x][y]; @@ -217,6 +208,14 @@ int x1, y1, x2, y2; } } +void +wallification(x1, y1, x2, y2) +int x1, y1, x2, y2; +{ + wall_cleanup(x1,y1,x2,y2); + fix_wall_spines(x1,y1,x2,y2); +} + STATIC_OVL boolean okay(x, y, dir) int x, y; From a329d7a6dd5ad1cc85b8029ee386741bed067be7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 5 Jan 2016 09:11:42 +0200 Subject: [PATCH 10/86] Capitalize Linux in guidebook --- doc/Guidebook.mn | 2 +- doc/Guidebook.tex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 0656e2f63..2efd8bbf2 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1948,7 +1948,7 @@ There is a section of this Guidebook that discusses that. .pg The default name of the configuration file varies on different operating systems. On DOS and Windows, it is ``defaults.nh'' -in the same folder as nethack.exe or nethackW.exe. On Unix, linux +in the same folder as nethack.exe or nethackW.exe. On Unix, Linux and Mac OS X it is ``.nethackrc'' in the user's home directory. NETHACKOPTIONS can also be set to the full name of a file you want to use (possibly preceded by an `@'). diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 5ccc9bdef..cbb63f7a0 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2347,7 +2347,7 @@ There is a section of this Guidebook that discusses that. %.pg The default name of the configuration file varies on different operating systems. On DOS and Windows, it is ``{\tt defaults.nh}'' -in the same folder as nethack.exe or nethackW.exe. On Unix, linux +in the same folder as nethack.exe or nethackW.exe. On Unix, Linux and Mac OS X it is ``{\tt.nethackrc}'' in the user's home directory. NETHACKOPTIONS can also be set to the full name of a file you want to use (possibly preceded by an `{\tt @}'). From 3506062c7d32f55aa34d2146d0b6354cd5ec9d42 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 5 Jan 2016 10:00:27 +0200 Subject: [PATCH 11/86] Fix bz270, H4166: Finding a secret corridor shows it unlit with lit_corridor Also #terrain command with dark_room on showed lit room floor on places with objects or traps. We don't want to show dark room symbol anyway, because the dark room symbols are only for line-of-sight, and #terrain should override that... --- src/detect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detect.c b/src/detect.c index 1e5b23edc..c29ad83eb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1363,7 +1363,7 @@ register int aflag; /* intrinsic autosearch vs explicit searching */ unblock_point(x, y); /* vision */ exercise(A_WIS, TRUE); nomul(0); - feel_location(x, y); /* make sure it shows up */ + feel_newsym(x, y); /* make sure it shows up */ You("find a hidden passage."); } else { /* Be careful not to find anything in an SCORR or SDOOR */ @@ -1553,6 +1553,8 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */ } } } + if (glyph == cmap_to_glyph(S_darkroom)) + glyph = cmap_to_glyph(S_room); /* FIXME: dirty hack */ show_glyph(x, y, glyph); } From 861afbb1c95dcb0ca5df9b10bc3f2a5c2d16c5e1 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 5 Jan 2016 12:09:40 +0200 Subject: [PATCH 12/86] Fix bz276,H4172: Fleeing monsters don't actually flee This fix comes via DynaHack by Tung Nguyen. --- src/monmove.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/monmove.c b/src/monmove.c index 8fc93b745..cae22b8b5 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -271,6 +271,8 @@ boolean fleemsg; } mtmp->mflee = 1; } + /* ignore recently-stepped spaces when made to flee */ + memset(mtmp->mtrack, MTSZ, sizeof(coord)); } STATIC_OVL void From e80a9e0dafc1df0c60d48c2bb04682a488bf33d5 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 5 Jan 2016 12:32:18 +0200 Subject: [PATCH 13/86] Make (level) teleporting clear monster movement tracking --- src/dog.c | 3 +-- src/teleport.c | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dog.c b/src/dog.c index efcb76892..361c7de02 100644 --- a/src/dog.c +++ b/src/dog.c @@ -325,8 +325,7 @@ boolean with_you; xyflags = mtmp->mtrack[0].y; xlocale = mtmp->mtrack[1].x; ylocale = mtmp->mtrack[1].y; - mtmp->mtrack[0].x = mtmp->mtrack[0].y = 0; - mtmp->mtrack[1].x = mtmp->mtrack[1].y = 0; + memset(mtmp->mtrack, MTSZ, sizeof(coord)); if (mtmp == u.usteed) return; /* don't place steed on the map */ diff --git a/src/teleport.c b/src/teleport.c index 5faf0135c..47780e7da 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -980,6 +980,7 @@ register int x, y; } } + memset(mtmp->mtrack, MTSZ, sizeof(coord)); place_monster(mtmp, x, y); /* put monster down */ update_monster_region(mtmp); From 1d097bf0dd08fdd6072e0cb49d3fe232fc82edb4 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Jan 2016 02:39:46 -0800 Subject: [PATCH 14/86] tribute: Equal Rites --- dat/tribute | 215 +++++++++++++++++++++++++++++++++++++++++++++----- doc/fixes36.1 | 2 +- 2 files changed, 196 insertions(+), 21 deletions(-) diff --git a/dat/tribute b/dat/tribute index 37eb2d374..6a7f63b31 100644 --- a/dat/tribute +++ b/dat/tribute @@ -384,13 +384,13 @@ GET TO THE BOTTOM OF THIS IF IT KILLS ME. FIGURATIVELY SPEAKING OF COURSE.' [The Light Fantastic, by Terry Pratchett] %e passage 2 -# p. 7 (passage starts mid-paragraph; the too-long-to-answer question is +# p. 7 (passage starts mid-sentence; the too-long-to-answer question is # "Why have Rincewind and Twoflower fallen off the Disc's rim?", # alluding to the conclusion of /The Colour of Magic/; # in /Sourcery/ and /Interesting Times/ and probably others, the # famous philosohper's name is spelled "Ly Tin Wheedle") %passage 3 -[...] such questions take time and could be more trouble than they are +[...] such questions take time and could be more trouble than they are worth. For example, it is said that someone at a party once asked the famous philosopher Ly Tin Weedle "Why are you here?" and the reply took three years. @@ -573,39 +573,204 @@ according its victims the dignity of hatred. It wouldn't even notice them. # # # -%title Equal Rites (3) +%title Equal Rites (9) +# p. 118 (Signet edition; passage starts mid-sentence and ends mid-paragraph) %passage 1 -...it is well known that a vital ingredient of success is not knowing that -what you're attempting can't be done. +[...] it is well known that a vital ingredient of success is not knowing +that what you're attempting can't be done. [...] [Equal Rites, by Terry Pratchett] %e passage +# p. 218 (speaker is Granny Weatherwax) %passage 2 -Million-to-one chances...crop up nine times out of ten. +"Million-to-one chances," she said, "crop up nine times out of ten." [Equal Rites, by Terry Pratchett] %e passage +# pp. 96-97 ('Tannoy': public address speaker) %passage 3 -Animal minds are simple, and therefore sharp. Animals never spend time -dividing experience into little bits and speculating about all the bits -they've missed. The whole panoply of the universe has been neatly -expressed to them as things to (a) mate with, (b) eat, (c) run away from, -and (d) rocks. This frees the mind from unnecessary thoughts and gives -it a cutting edge where it matters. Your normal animal, in fact, never -tries to walk and chew gum at the same time. +Animal minds are simple, and therefore sharp. Animals never spend time +dividing experience into little bits and speculating about all the bits +they've missed. The whole panoply of the universe has been neatly +expressed to them as things to (a) mate with, (b) eat, (c) run away from, +and (d) rocks. This frees the mind from unnecessary thoughts and gives +it a cutting edge where it matters. Your normal animal, in fact, never +tries to walk and chew gum at the same time. -The average human, on the other hand, thinks about all sorts of things +The average human, on the other hand, thinks about all sorts of things around the clock, on all sorts of levels, with interruptions from dozens -of biological calendars and timepieces. There's thoughts about to be said, -and private thoughts, and real thoughts, and thoughts about thoughts, and -a whole gamut of subconscious thoughts. To a telepath the human head is -a din. It is a railway terminus with all the Tannoys talking at once. -It is a complete FM waveband- and some of those stations aren't reputable, +of biological calendars and timepieces. There's thoughts about to be said, +and private thoughts, and real thoughts, and thoughts about thoughts, and +a whole gamut of subconscious thoughts. To a telepath the human head is +a din. It is a railway terminus with all the Tannoys talking at once. +It is a complete FM waveband--and some of those stations aren't reputable, they're outlawed pirates on forbidden seas who play late-night records with limbic lyrics. [Equal Rites, by Terry Pratchett] %e passage +# pp. 18-19 +%passage 4 +Smith took a spade from beside the back door and hesitated. + +"Granny." + +"What?" + +"Do you know how wizards like to be buried?" + +"Yes!" + +"Well, how?" + +Granny paused at the bottom of the stairs. + +"Reluctantly." + + [Equal Rites, by Terry Pratchett] +%e passage +# p. 70 +%passage 5 +Granny sighed. "You have learned something," she said, and thought it +was safe to insert a touch of sternness into her voice. "They say that a +little knowledge is a dangerous thing, but it is not one half so bad as a +lot of ignorance." + + [Equal Rites, by Terry Pratchett] +%e passage +# pp. 113-114 (Esk is a young girl) +%passage 6 +The barges stopped at some of the towns. By tradition only the men went +ashore, and only Amschat, wearing his ceremonial Lying hat, spoke to +non-Zoons. Esk usually went with him. He tried hinting that she should +obey the unwritten rules of Zoon life and stay afloat, but a hint was to +Esk what a mosquito bite was to the average rhino because she was already +learning that if you ignore the rules people will, half the time, quietly +rewrite them so that they don't apply to you. + + [Equal Rites, by Terry Pratchett] +%e passage +# pp. 119-120 ("what is happening here?" actually omits "is" but +# must be a typo--fixed here to avoid bug reports; +# 'broomstick' is Esk's disguised wizard's staff; +# passage continues with questions about destination and +# why go overland when the river goes to the same place) +%passage 7 +The town was smaller than Ohulan, and very different because it lay on the +junction of three trade routes quite apart from the river itself. It was +built around one enormous square which was a cross between a permanent +exotic traffic jam and a tent village. Camels kicked mules, mules kicked +horses, horses kicked camels and they all kicked humans; there was a riot +of colours, a din of noise, a nasal orchestration of smells and the steady, +heady sound of hundreds of people working hard at making money. + +One reason for the bustle was that over large parts of the continent other +people preferred to make money without working at all, and since the Disc +had yet to develop a music recording industry they were forced to fall back +on older, more traditional forms of banditry. + +Strangely enough these often involved considerable effort. Rolling heavy +rocks to the top of cliffs for a decent ambush, cutting down trees to +block the road, and digging a pit lined with spikes while still keeping a +wicked edge on a dagger probably involved a much greater expenditure of +thought and muscle than more socially-acceptable professions but, +nevertheless, there were still people misguided enough to endure all this, +plus long nights in uncomfortable surroundings, merely to get their hands +on perfectly ordinary large boxes of jewels. + +So a town like Zemphis was the place where caravans split, mingled and +came together again, as dozens of merchants and travellers banded together +for protection against the socially disadvantaged on the trails ahead. +Esk, wandering unregarded amidst the bustle, learned all this by the simple +method of finding someone who looked important and tugging on the hem of +his coat. + +This particular man was counting bales of tobacco and would have succeeded +but for the interruption. + +"What?" + +"I said, what is happening here?" + +The man meant to say: "Push off and bother someone else." He meant to +give her a light cuff about the head. So he was astonished to find himself +bending down and talking seriously to a small, grubby-faced child holding +a large broomstick (which also, it seemed to him later, was in some +indefinable way /paying attention/). + +He explained about the caravans. The child nodded. + +"People all get together to travel?" + +"Precisely." + + [Equal Rites, by Terry Pratchett] +%e passage +# pp. 127-128 (this time broomstick is Granny's defective witch's broomstick) +%passage 8 +The broomstick lay between two trestles. Granny Weatherwax sat on a rock +outcrop while a dwarf half her height, wearing an apron that was a mass of +pockets, walked around the broom and occasionally poked it. + +Eventually he kicked the bristles and gave a long intake of breath, a sort +of reverse whistle, which is the secret sign of craftsman across the +universe and means that something expensive is about to happen. + +"Weellll," he said. "I could get the apprentices in to look at this, I +could. It's an education in itself. And you say it actually managed to +get airborne?" + +"It flew like a bird," said Granny. + +The dwarf lit a pipe. "I should very much like to see that bird," he said +reflectively. "I should imagine it's quite something to watch, a bird like +that." + +"Yes, but can you repair it?" said Granny. "I'm in a hurry." + +The dwarf sat down, slowly and deliberately. + +"As for /repair/," he said, "well, I don't know about /repair/. Rebuild, +maybe. Of course, it's hard to get the bristles these days even if you can +find people to do the proper binding, and the spells need--" + +"I don't want it rebuilt, I just want it to work properly," said Granny. + +"It's an early model, you see," the dwarf plugged on. "Very tricky, those +early models. You can't get the wood--" + +He was picked up bodily until his eyes were level with Granny's. Dwarves, +being magical in themselves as it were, are quite resistant to magic but +her expression looked as though she was trying to weld his eyeballs to the +back of his skull. + +"Just repair it," she hissed. "Please?" + +"What, make a bodge job?" said the dwarf, his pipe clattering to the floor. + +"Yes." + +"Patch it up, you mean? Betray my training by doing half a job?" + +"Yes," said Granny. Her pupils were two little black holes. + +"Oh," said the dwarf. "Right, then." + + [Equal Rites, by Terry Pratchett] +%e passage +# p. 185 (actually uses four periods to mark a sentence ending in a elipsis) +%passage 9 +There may be universes where librarianship is considered a peaceful sort of +occupation, and where the risks are limited to large volumes falling off +the shelves on to one's head, but the keeper of a /magic/ library is no job +for the unwary. Spells have power, and merely writing them down and +shoving them between covers doesn't do anything to reduce it. The stuff +leaks. Books tend to react with one another, creating randomized magic +with a mind of its own. Books of magic are usually chained to their +shelves, but not to prevent them being stolen.... + + [Equal Rites, by Terry Pratchett] +%e passage %e title # # @@ -6200,7 +6365,7 @@ IF YOU ASK ME, said Death, NOBODY COULD DO ANY BETTER THAN THAT... # Used for interaction with Death. # %section Death -%title Death Quotes (13) +%title Death Quotes (17) %passage 1 WHERE THE FIRST PRIMAL CELL WAS, THERE WAS I ALSO. WHERE MAN IS, THERE AM I. WHEN THE LAST LIFE CRAWLS UNDER FREEZING STARS, THERE WILL I BE. %e passage @@ -6253,6 +6418,16 @@ I HAVE COME FOR THEE. # including them here wouldn't fit with the rest) %passage 14 DARK IN HERE, ISN'T IT? +# p. 14 (Equal Rites; 2nd sentence continues 'said the deep, heavy voice...') +%passage 15 +THERE IS NO GOING BACK. THERE IS NO GOING BACK. +# p. 15 (contradicts later descriptions of Death as existing outside of time; +# presumably it's just intended as a colloquial expression) +%passage 16 +I HAVEN'T GOT ALL DAY, YOU KNOW. +# p. 15 (same page) +%passage 17 +LIFE IS FOR THE LIVING. %e title %e section # diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 0ab9f3a43..e531f6e1d 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -116,7 +116,7 @@ reading non-cursed scroll of enchant weapon uncurses welded tin opener if hero has no jumping ability but knows the jumping spell, the #jump command will attempt to cast the spell additional tribute passages for The Colour of Magic, The Light Fantastic, - Snuff, and Raising Steam + Equal Rites, Snuff, and Raising Steam compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use From 192d1bd89e681f54d380eb124604c4d201308720 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 5 Jan 2016 12:59:54 +0200 Subject: [PATCH 15/86] Add mtrack changes to fixes file --- doc/fixes36.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index e531f6e1d..51e27e78d 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -82,6 +82,7 @@ ensure sufficient messages are given to clarify the transition from detected fix "killing by kicking something weird" when kicking an object causes death guard macros available for mextra fields similar to those for oextra fields compile-time option for an alternate paniclog format for public server use +make monsters forget where they stepped when fleeing or teleporting Platform- and/or Interface-Specific Fixes From e92b80b2ab86398f31598d1b2bef5bdc5a9ac0a1 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 00:52:51 +0200 Subject: [PATCH 16/86] Requiver pickup_thrown objects if quiver is empty Change via Dynahack by Tung Nguyen --- doc/fixes36.1 | 1 + src/invent.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 51e27e78d..ec5d44b9e 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -83,6 +83,7 @@ fix "killing by kicking something weird" when kicking an object causes death guard macros available for mextra fields similar to those for oextra fields compile-time option for an alternate paniclog format for public server use make monsters forget where they stepped when fleeing or teleporting +requiver pickup_thrown objects if quiver is empty Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index 3f0c15b85..1e220bbc4 100644 --- a/src/invent.c +++ b/src/invent.c @@ -434,6 +434,7 @@ struct obj *obj; { struct obj *otmp, *prev; int saved_otyp = (int) obj->otyp; /* for panic */ + boolean obj_was_thrown; if (obj->where != OBJ_FREE) panic("addinv: obj not free"); @@ -442,6 +443,7 @@ struct obj *obj; obj->no_charge = 0; /* should not be set in hero's invent */ if (Has_contents(obj)) picked_container(obj); /* clear no_charge */ + obj_was_thrown = obj->was_thrown; obj->was_thrown = 0; /* not meaningful for invent */ addinv_core1(obj); @@ -476,6 +478,9 @@ struct obj *obj; } obj->where = OBJ_INVENT; + /* fill empty quiver if obj was thrown */ + if (flags.pickup_thrown && !uquiver && obj_was_thrown) + setuqwep(obj); added: addinv_core2(obj); carry_obj_effects(obj); /* carrying affects the obj */ From a049cd070b60879a97b3334438593542b0fe9085 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 01:04:56 +0200 Subject: [PATCH 17/86] Never route a travel path through boulders in Sokoban Change via Dynahack by Tung Nguyen --- src/hack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hack.c b/src/hack.c index 3f6514678..6305ad1e7 100644 --- a/src/hack.c +++ b/src/hack.c @@ -827,6 +827,9 @@ int mode; } else if (mode == TEST_TRAV) { struct obj *obj; + /* never travel through boulders in Sokoban */ + if (Sokoban) return FALSE; + /* don't pick two boulders in a row, unless there's a way thru */ if (sobj_at(BOULDER, ux, uy) && !Sokoban) { if (!Passes_walls From db4120012dd4e18fa3402716cd671df5af24ad62 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 01:44:18 +0200 Subject: [PATCH 18/86] Make mimics mimicing walls or trees also block light --- doc/fixes36.1 | 1 + include/monst.h | 10 ++++++++++ src/display.c | 3 +-- src/mon.c | 3 +-- src/vision.c | 4 ++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index ec5d44b9e..b44ce9f4b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -84,6 +84,7 @@ guard macros available for mextra fields similar to those for oextra fields compile-time option for an alternate paniclog format for public server use make monsters forget where they stepped when fleeing or teleporting requiver pickup_thrown objects if quiver is empty +make mimics mimicing walls or trees also block light Platform- and/or Interface-Specific Fixes diff --git a/include/monst.h b/include/monst.h index 3c88d0172..7196026f9 100644 --- a/include/monst.h +++ b/include/monst.h @@ -159,6 +159,16 @@ struct monst { #define is_vampshifter(mon) \ ((mon)->cham == PM_VAMPIRE || (mon)->cham == PM_VAMPIRE_LORD \ || (mon)->cham == PM_VLAD_THE_IMPALER) + +/* mimic appearances that block vision/light */ +#define is_lightblocker_mappear(mon) \ + (is_obj_mappear(mon, BOULDER) || \ + ((mon)->m_ap_type == M_AP_FURNITURE \ + && ((mon)->mappearance == S_hcdoor \ + || (mon)->mappearance == S_vcdoor \ + || (mon)->mappearance < S_ndoor /* = walls */ \ + || (mon)->mappearance == S_tree))) + #define is_door_mappear(mon) ((mon)->m_ap_type == M_AP_FURNITURE \ && ((mon)->mappearance == S_hcdoor || (mon)->mappearance == S_vcdoor)) #define is_obj_mappear(mon,otyp) ((mon)->m_ap_type == M_AP_OBJECT \ diff --git a/src/display.c b/src/display.c index e75f74d53..333ed4d5b 100644 --- a/src/display.c +++ b/src/display.c @@ -1201,8 +1201,7 @@ set_mimic_blocking() for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; - if (mon->minvis && (is_door_mappear(mon) - || is_obj_mappear(mon,BOULDER))) { + if (mon->minvis && is_lightblocker_mappear(mon)) { if (See_invisible) block_point(mon->mx, mon->my); else diff --git a/src/mon.c b/src/mon.c index 40cdb0dca..3c272cbc7 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2616,8 +2616,7 @@ void seemimic(mtmp) register struct monst *mtmp; { - boolean is_blocker_appear = (is_door_mappear(mtmp) - || is_obj_mappear(mtmp, BOULDER)); + boolean is_blocker_appear = (is_lightblocker_mappear(mtmp)); if (has_mcorpsenm(mtmp)) freemcorpsenm(mtmp); diff --git a/src/vision.c b/src/vision.c index 77475af96..2dcc85b8b 100644 --- a/src/vision.c +++ b/src/vision.c @@ -175,9 +175,9 @@ register struct rm *lev; if (obj->otyp == BOULDER) return 1; - /* Mimics mimicing a door or boulder block light. */ + /* Mimics mimicing a door or boulder or ... block light. */ if ((mon = m_at(x, y)) && (!mon->minvis || See_invisible) - && (is_door_mappear(mon) || is_obj_mappear(mon,BOULDER))) + && is_lightblocker_mappear(mon)) return 1; return 0; From fd709d68400621439b8fa6ec1fbd3a2f4fbdd17b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 01:53:44 +0200 Subject: [PATCH 19/86] Clear mimic vision blocking after genocide Fix via Dynahack by Tung Nguyen --- src/mon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mon.c b/src/mon.c index 3c272cbc7..08333c250 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1653,6 +1653,8 @@ struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ remove_monster(mtmp->mx, mtmp->my); if (emits_light(mptr)) del_light_source(LS_MONSTER, monst_to_any(mtmp)); + if (mtmp->m_ap_type) + seemimic(mtmp); newsym(mtmp->mx, mtmp->my); unstuck(mtmp); fill_pit(mtmp->mx, mtmp->my); From d598cf536b05b7238f3f61ed18a63af34dcee1a2 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Jan 2016 16:17:38 -0800 Subject: [PATCH 20/86] fix #H4179 - lava vs boots Stepping onto lava destroyed water walking boots if they weren't fireproof but didn't do that for other types of boots unless hero was not fire resistant and got killed by the lava. Burn up all non-fireproof leather boots when stepping onto lava. --- doc/fixes36.1 | 2 ++ src/trap.c | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index b44ce9f4b..436a270b9 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -85,6 +85,8 @@ compile-time option for an alternate paniclog format for public server use make monsters forget where they stepped when fleeing or teleporting requiver pickup_thrown objects if quiver is empty make mimics mimicing walls or trees also block light +stepping onto lava destroyed non-fireproof water walking boots but left other + vulnerable boot types intact Platform- and/or Interface-Specific Fixes diff --git a/src/trap.c b/src/trap.c index b5cda7a5b..7f9a1ea7d 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1451176031 2015/12/27 00:27:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.252 $ */ +/* NetHack 3.6 trap.c $NHDT-Date: 1452039453 2016/01/06 00:17:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.253 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4999,13 +4999,13 @@ lava_effects() && objects[obj->otyp].oc_oprop != FIRE_RES && obj->otyp != SCR_FIRE && obj->otyp != SPE_FIREBALL && !obj_resists(obj, 0, 0)) /* for invocation items */ - obj->in_use = TRUE; + obj->in_use = 1; /* Check whether we should burn away boots *first* so we know whether to * make the player sink into the lava. Assumption: water walking only * comes from boots. */ - if (Wwalking && uarmf && is_organic(uarmf) && !uarmf->oerodeproof) { + if (uarmf && is_organic(uarmf) && !uarmf->oerodeproof) { obj = uarmf; pline("%s into flame!", Yobjnam2(obj, "burst")); iflags.in_lava_effects++; /* (see above) */ @@ -5119,6 +5119,9 @@ sink_into_lava() You("sink below the surface and die."); burn_away_slime(); /* add insult to injury? */ done(DISSOLVED); + /* can only get here via life-saving; try to get away from lava */ + u.utrap = 0; + (void) safe_teleds(TRUE); } else if (!u.umoved) { /* can't fully turn into slime while in lava, but might not have it be burned away until you've come awfully close */ From 2c9ae20c5a99e498514336e94d9f22f227a43640 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:04:13 +0200 Subject: [PATCH 21/86] Allow quickly moving cursor on monsters Original patch was mine, but this implementation took ideas from Dynahack by Tung Nguyen --- doc/fixes36.1 | 1 + src/do_name.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 436a270b9..16f77f7e7 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -87,6 +87,7 @@ requiver pickup_thrown objects if quiver is empty make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact +allow moving cursor to monsters with 'm' and 'M' when asked for map location Platform- and/or Interface-Specific Fixes diff --git a/src/do_name.c b/src/do_name.c index 889609034..5e5675b98 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -55,6 +55,7 @@ const char *goal; putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time."); putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); putstr(tmpwin, 0, "Use @ to move the cursor on yourself."); + putstr(tmpwin, 0, "Use m or M to move the cursor on monster."); if (getpos_hilitefunc) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); @@ -71,6 +72,25 @@ const char *goal; destroy_nhwindow(tmpwin); } +static int +cmp_coord_distu(a, b) +const void *a; +const void *b; +{ + const coord *c1 = a; + const coord *c2 = b; + int dx, dy, dist1, dist2; + + dx = u.ux - c1->x; + dy = u.uy - c1->y; + dist1 = dx * dx + dy * dy; + dx = u.ux - c2->x; + dy = u.uy - c2->y; + dist2 = dx * dx + dy * dy; + + return dist1 - dist2; +} + int getpos(ccp, force, goal) coord *ccp; @@ -85,6 +105,9 @@ const char *goal; static const char pick_chars[] = ".,;:"; const char *cp; boolean hilite_state = FALSE; + coord *monarr = NULL; + int moncount = 0; + int monidx = 0; if (!goal) goal = "desired location"; @@ -217,6 +240,43 @@ const char *goal; cx = u.ux; cy = u.uy; goto nxtc; + } else if (c == 'm' || c == 'M') { + if (!monarr) { + moncount = 0; + monidx = 0; + struct monst *mtmp = fmon; + while (mtmp) { + if (canspotmon(mtmp) + && (mtmp->mx != u.ux && mtmp->my != u.uy)) + moncount++; + mtmp = mtmp->nmon; + } + monarr = (coord *)alloc(sizeof(coord) * moncount); + mtmp = fmon; + while (mtmp) { + if (canspotmon(mtmp) + && (mtmp->mx != u.ux && mtmp->my != u.uy)) { + monarr[monidx].x = mtmp->mx; + monarr[monidx].y = mtmp->my; + monidx++; + } + mtmp = mtmp->nmon; + } + qsort(monarr, moncount, sizeof(coord), cmp_coord_distu); + /* ready this for first increment/decrement to change to zero */ + monidx = (c == 'm') ? -1 : 1; + } + if (moncount) { + if (c == 'm') + monidx = (monidx + 1) % moncount; + else { + monidx--; + if (monidx < 0) monidx = moncount-1; + } + cx = monarr[monidx].x; + cy = monarr[monidx].y; + goto nxtc; + } } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; @@ -307,6 +367,8 @@ const char *goal; clear_nhwindow(WIN_MESSAGE); ccp->x = cx; ccp->y = cy; + if (monarr) + free(monarr); getpos_hilitefunc = (void FDECL((*), (int))) 0; return result; } From 31f883da0da89b3cf72455192cb71256f17d0ca6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:17:32 +0200 Subject: [PATCH 22/86] Use appropriate place description for drum of earthquake shake Fix via Dynahack by Tung Nguyen --- src/music.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/music.c b/src/music.c index 89ff06127..73b855bc1 100644 --- a/src/music.c +++ b/src/music.c @@ -426,6 +426,23 @@ int force; } } +const char * +generic_lvl_desc() +{ + if (Is_astralevel(&u.uz)) + return "astral plane"; + else if (In_endgame(&u.uz)) + return "plane"; + else if (Is_sanctum(&u.uz)) + return "sanctum"; + else if (In_sokoban(&u.uz)) + return "puzzle"; + else if (In_V_tower(&u.uz)) + return "tower"; + else + return "dungeon"; +} + /* * The player is trying to extract something from his/her instrument. */ @@ -537,7 +554,8 @@ struct obj *instr; consume_obj_charge(instr, TRUE); You("produce a heavy, thunderous rolling!"); - pline_The("entire dungeon is shaking around you!"); + pline_The("entire %s is shaking around you!", + generic_lvl_desc()); do_earthquake((u.ulevel - 1) / 3 + 1); /* shake up monsters in a much larger radius... */ awaken_monsters(ROWNO * COLNO); From ed1c592a9ae062d8b0398c2b09f9e1889d367bfa Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:23:24 +0200 Subject: [PATCH 23/86] Remove double defines of hunger states --- src/apply.c | 2 -- src/shk.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/apply.c b/src/apply.c index 0af45749a..0136421d3 100644 --- a/src/apply.c +++ b/src/apply.c @@ -773,8 +773,6 @@ beautiful() : "ugly"); } -#define WEAK 3 /* from eat.c */ - static const char look_str[] = "look %s."; STATIC_OVL int diff --git a/src/shk.c b/src/shk.c index ca3893b1f..b2208d399 100644 --- a/src/shk.c +++ b/src/shk.c @@ -3118,8 +3118,6 @@ quit: return 0; } -#define HUNGRY 2 - STATIC_OVL long getprice(obj, shk_buying) register struct obj *obj; From de5ed30cd7cadcaabbbc6553c9ffcddce7a397d2 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Jan 2016 17:29:36 -0800 Subject: [PATCH 24/86] fix #H4179 - death reason for rotted globs 'Poisoned by a rotted gray ooze corpse' should have been 'Poisoned by a rotted glob of gray ooze'. eatcorpse() is called for non-corpse globs and then corpse_xname() is called for them too to set up death reason for make_sick(), but it didn't know anything about globs. Now it does. Blob size is ignored since it's not relevant for cause of death. --- doc/fixes36.1 | 1 + src/objnam.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 16f77f7e7..dbbc0b0a6 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -88,6 +88,7 @@ make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact allow moving cursor to monsters with 'm' and 'M' when asked for map location +fix death reason when eating tainted glob of (not corpse) Platform- and/or Interface-Specific Fixes diff --git a/src/objnam.c b/src/objnam.c index 339a478a5..5dc1e8c2e 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objnam.c $NHDT-Date: 1451683056 2016/01/01 21:17:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.162 $ */ +/* NetHack 3.6 objnam.c $NHDT-Date: 1452043772 2016/01/06 01:29:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.163 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1102,6 +1102,8 @@ register struct obj *otmp; || is_flammable(otmp)); } +/* format a corpse name (xname() omits monster type; doname() calls us); + eatcorpse() also uses us for death reason when eating tainted glob */ char * corpse_xname(otmp, adjective, cxn_flags) struct obj *otmp; @@ -1118,10 +1120,14 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ /* include "an" for "an ogre corpse */ any_prefix = (cxn_flags & CXN_ARTICLE) != 0, /* leave off suffix (do_name() appends "corpse" itself) */ - omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, possessive = FALSE; + omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, + possessive = FALSE, + glob = (otmp->otyp != CORPSE && otmp->globby); const char *mname; - if (omndx == NON_PM) { /* paranoia */ + if (glob) { + mname = OBJ_NAME(objects[otmp->otyp]); /* "glob of " */ + } else if (omndx == NON_PM) { /* paranoia */ mname = "thing"; /* [Possible enhancement: check whether corpse has monster traits attached in order to use priestname() for priests and minions.] */ @@ -1172,7 +1178,9 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ any_prefix = FALSE; } - if (!omit_corpse) { + if (glob) { + ; /* omit_corpse doesn't apply; quantity is always 1 */ + } else if (!omit_corpse) { Strcat(nambuf, " corpse"); /* makeplural(nambuf) => append "s" to "corpse" */ if (otmp->quan > 1L && !ignore_quan) { From f314fe87bdeb9ed83c1409ca384a56141d5f8b7b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:32:42 +0200 Subject: [PATCH 25/86] Fix unmapped branch stairs on premapped levels This happens when levelporting to the first Sokoban level in wizard mode before visiting the level, causing the branch stairs to not appear until the space it is in comes in sight of the player. The issue was that levels flagged premapped would cause the special level coder to call sokoban_detect() before fixup_special() had a chance to place the branch stairs properly. Fix from Dynahack by Tung Nguyen. --- include/extern.h | 1 + src/mkmaze.c | 4 +--- src/sp_lev.c | 9 +++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/extern.h b/include/extern.h index 49ed2ec6a..1c9c9af6d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1201,6 +1201,7 @@ E boolean FDECL(bad_location, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E void FDECL(place_lregion, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, d_level *)); +E void NDECL(fixup_special); E void NDECL(fumaroles); E void NDECL(movebubbles); E void NDECL(water_friction); diff --git a/src/mkmaze.c b/src/mkmaze.c index f192a3f3c..246dafea4 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -19,7 +19,6 @@ STATIC_DCL void FDECL(maze0xy, (coord *)); STATIC_DCL boolean FDECL(put_lregion_here, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, BOOLEAN_P, d_level *)); -STATIC_DCL void NDECL(fixup_special); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); @@ -362,7 +361,7 @@ d_level *lev; static boolean was_waterlevel; /* ugh... this shouldn't be needed */ /* this is special stuff that the level compiler cannot (yet) handle */ -STATIC_OVL void +void fixup_special() { register lev_region *r = lregions; @@ -577,7 +576,6 @@ register const char *s; if (*protofile) { Strcat(protofile, LEV_EXT); if (load_special(protofile)) { - fixup_special(); /* some levels can end up with monsters on dead mon list, including light source monsters */ dmonsfree(); diff --git a/src/sp_lev.c b/src/sp_lev.c index 61740b436..79a3bbcc8 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -5863,11 +5863,16 @@ sp_lev *lvl; count_features(); - if (coder->premapped) - sokoban_detect(); if (coder->solidify) solidify_map(); + /* This must be done before sokoban_detect(), + * otherwise branch stairs won't be premapped. */ + fixup_special(); + + if (coder->premapped) + sokoban_detect(); + if (coder->frame) { struct sp_frame *tmpframe; do { From 4d919b4d1f7bdc665cb71ad98a8a2a8daed5792f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:37:35 +0200 Subject: [PATCH 26/86] Update fixes entries --- doc/fixes36.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index dbbc0b0a6..ab6ab16d7 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -89,6 +89,8 @@ stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact allow moving cursor to monsters with 'm' and 'M' when asked for map location fix death reason when eating tainted glob of (not corpse) +use appropriate place name for drum of earthquake shakes +fix unmapped branch stairs on sokoban level Platform- and/or Interface-Specific Fixes From 6b559d06f0f938e86ca4c2d94e5b09c2d4acb7f9 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 04:41:57 +0200 Subject: [PATCH 27/86] Redraw map when hilite_pile is toggled --- doc/fixes36.1 | 1 + src/options.c | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index ab6ab16d7..eae8a53ff 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -91,6 +91,7 @@ allow moving cursor to monsters with 'm' and 'M' when asked for map location fix death reason when eating tainted glob of (not corpse) use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level +redraw map when hilite_pile is toggled to display the highlighting Platform- and/or Interface-Specific Fixes diff --git a/src/options.c b/src/options.c index 3e923e046..11a26c074 100644 --- a/src/options.c +++ b/src/options.c @@ -3384,6 +3384,7 @@ boolean tinitial, tfrom_file; need_redraw = TRUE; /* darkroom refresh */ } else if ((boolopt[i].addr) == &iflags.use_inverse || (boolopt[i].addr) == &flags.showrace + || (boolopt[i].addr) == &iflags.hilite_pile || (boolopt[i].addr) == &iflags.hilite_pet) { need_redraw = TRUE; #ifdef TEXTCOLOR From 4aeb2913cf58848ee4e3dadee59fffb737358f5f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 04:58:37 +0200 Subject: [PATCH 28/86] Only requiver pickup_thrown ammo and throwing weapons --- include/extern.h | 1 + src/dothrow.c | 3 +-- src/invent.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/extern.h b/include/extern.h index 1c9c9af6d..5585692e0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -498,6 +498,7 @@ E void FDECL(endmultishot, (BOOLEAN_P)); E void FDECL(hitfloor, (struct obj *)); E void FDECL(hurtle, (int, int, int, BOOLEAN_P)); E void FDECL(mhurtle, (struct monst *, int, int, int)); +E boolean FDECL(throwing_weapon, (struct obj *)); E void FDECL(throwit, (struct obj *, long, BOOLEAN_P)); E int FDECL(omon_adj, (struct monst *, struct obj *, BOOLEAN_P)); E int FDECL(thitmonst, (struct monst *, struct obj *)); diff --git a/src/dothrow.c b/src/dothrow.c index 8de02854d..fa02a1186 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -16,7 +16,6 @@ STATIC_DCL void FDECL(check_shop_obj, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); STATIC_DCL void FDECL(breakmsg, (struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(toss_up, (struct obj *, BOOLEAN_P)); -STATIC_DCL boolean FDECL(throwing_weapon, (struct obj *)); STATIC_DCL void FDECL(sho_obj_return_to_u, (struct obj * obj)); STATIC_DCL boolean FDECL(mhurtle_step, (genericptr_t, int, int)); @@ -943,7 +942,7 @@ boolean hitsroof; } /* return true for weapon meant to be thrown; excludes ammo */ -STATIC_OVL boolean +boolean throwing_weapon(obj) struct obj *obj; { diff --git a/src/invent.c b/src/invent.c index 1e220bbc4..0dd93861c 100644 --- a/src/invent.c +++ b/src/invent.c @@ -479,7 +479,8 @@ struct obj *obj; obj->where = OBJ_INVENT; /* fill empty quiver if obj was thrown */ - if (flags.pickup_thrown && !uquiver && obj_was_thrown) + if (flags.pickup_thrown && !uquiver && obj_was_thrown + && (throwing_weapon(obj) || is_ammo(obj))) setuqwep(obj); added: addinv_core2(obj); From cb4bb726314eedfd65d011516f714da9ec777046 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Jan 2016 23:19:14 -0800 Subject: [PATCH 29/86] fix getpos() m,M to move to next monster Fixing a couple of warnings led to discovery of a couple of real bugs. Warnings: 1) -Wshadow warning for 'dist2' variable blocking access to dist2() function. 2) Declaration not at top of block not allowed for C89/C90 (let alone for pre-ANSI). Bugs: 3) there might be 0 visible monsters, in which case the code prior to qsort will call alloc(0). I think ANSI requires malloc(0) to return a unique pointer which can be freed, but pre-ANSI malloc might return Null to satisfy it, leading to panic from nethack's alloc(). 4) visible monsters in direct line with hero horizontally or vertically were unintentionally skipped when collecting monster locations. I think looking at monsters is the wrong way to implement this. It should be scanning the map for monster glyphs instead. (Coin toss as to whether it should also treat statues-shown-as-monsters as if they were monsters while doing this. I'm leaning towards yes. And what about warning glyphs and instances of the remembered-invisible monster glyph? They aren't interesting to look at but they might provide a shortcut to positioning the cursor near something else.) Using '^' to move to next trap moves from hero's position to end of hero's line, then columns 1 to N of next line, and so on to bottom right, then top left columns 1 to N, second line 1 to N, on down to hero's line. Having 'm' traverse monsters from nearest to farthest feels like a noticeable inconsistency between the two. Especially if you move the cursor with direction or topology keystrokes prior to 'm'. --- src/do_name.c | 54 ++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 5e5675b98..567720e67 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1450178550 2015/12/15 11:22:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.80 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1452064740 2016/01/06 07:19:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.84 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,6 +6,8 @@ STATIC_DCL char *NDECL(nextmbuf); STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *)); +STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, + const void *)); STATIC_DCL void NDECL(do_mname); STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *)); STATIC_DCL void FDECL(do_oname, (struct obj *)); @@ -30,7 +32,7 @@ nextmbuf() /* function for getpos() to highlight desired map locations. * parameter value 0 = initialize, 1 = highlight, 2 = done */ -void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0; +static void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0; void getpos_sethilite(f) @@ -55,7 +57,7 @@ const char *goal; putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time."); putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); putstr(tmpwin, 0, "Use @ to move the cursor on yourself."); - putstr(tmpwin, 0, "Use m or M to move the cursor on monster."); + putstr(tmpwin, 0, "Use m or M to move the cursor to next monster."); if (getpos_hilitefunc) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); @@ -72,23 +74,23 @@ const char *goal; destroy_nhwindow(tmpwin); } -static int +STATIC_OVL int cmp_coord_distu(a, b) const void *a; const void *b; { const coord *c1 = a; const coord *c2 = b; - int dx, dy, dist1, dist2; + int dx, dy, dist_1, dist_2; dx = u.ux - c1->x; dy = u.uy - c1->y; - dist1 = dx * dx + dy * dy; + dist_1 = dx * dx + dy * dy; dx = u.ux - c2->x; dy = u.uy - c2->y; - dist2 = dx * dx + dy * dy; + dist_2 = dx * dx + dy * dy; - return dist1 - dist2; + return dist_1 - dist_2; } int @@ -215,7 +217,7 @@ const char *goal; if (c == '?' || redraw_cmd(c)) { if (c == '?') getpos_help(force, goal); - else /* ^R */ + else /* ^R */ docrt(); /* redraw */ /* update message window to reflect that we're still targetting */ show_goal_msg = TRUE; @@ -242,36 +244,35 @@ const char *goal; goto nxtc; } else if (c == 'm' || c == 'M') { if (!monarr) { + struct monst *mtmp; + moncount = 0; - monidx = 0; - struct monst *mtmp = fmon; - while (mtmp) { + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (canspotmon(mtmp) - && (mtmp->mx != u.ux && mtmp->my != u.uy)) + && (mtmp->mx != u.ux || mtmp->my != u.uy)) moncount++; - mtmp = mtmp->nmon; } - monarr = (coord *)alloc(sizeof(coord) * moncount); - mtmp = fmon; - while (mtmp) { + /* moncount + 1: always allocate a non-zero amount */ + monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); + monidx = 0; + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (canspotmon(mtmp) - && (mtmp->mx != u.ux && mtmp->my != u.uy)) { + && (mtmp->mx != u.ux || mtmp->my != u.uy)) { monarr[monidx].x = mtmp->mx; monarr[monidx].y = mtmp->my; monidx++; } - mtmp = mtmp->nmon; } - qsort(monarr, moncount, sizeof(coord), cmp_coord_distu); - /* ready this for first increment/decrement to change to zero */ + qsort(monarr, moncount, sizeof (coord), cmp_coord_distu); + /* ready for first increment/decrement to change to zero */ monidx = (c == 'm') ? -1 : 1; } if (moncount) { - if (c == 'm') + if (c == 'm') { monidx = (monidx + 1) % moncount; - else { - monidx--; - if (monidx < 0) monidx = moncount-1; + } else { + if (--monidx < 0) + monidx = moncount - 1; } cx = monarr[monidx].x; cy = monarr[monidx].y; @@ -281,6 +282,7 @@ const char *goal; if (!index(quitchars, c)) { char matching[MAXPCHARS]; int pass, lo_x, lo_y, hi_x, hi_y, k = 0; + (void) memset((genericptr_t) matching, 0, sizeof matching); for (sidx = 1; sidx < MAXPCHARS; sidx++) if (c == defsyms[sidx].sym || c == (int) showsyms[sidx]) @@ -368,7 +370,7 @@ const char *goal; ccp->x = cx; ccp->y = cy; if (monarr) - free(monarr); + free((genericptr_t) monarr); getpos_hilitefunc = (void FDECL((*), (int))) 0; return result; } From e6fa0ce809c106f7872c0aef01dbcd7268c5fd2e Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 00:07:54 -0800 Subject: [PATCH 30/86] provisional fix for bz239 - '[tty] Enter key...' '... inconsistency in character creation menus'. During role selection, the final 'is this ok?' menu has 'yes' preselected so accepted or to answer yes. The pick-role, pick-race, &c menus prior to getting to that stage didn't have a default, so using meant nothing was chosen, and choosing nothing was treated as a request to quit. This changes that so it's a request for 'random' instead. 'Provisional fix' because it ought to do this by making 'random' be a pre-selected menu entry so that the default choice is visible. But that takes more effort than I'm inclined to expend on this. --- doc/fixes36.1 | 2 ++ win/tty/wintty.c | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index eae8a53ff..dee5ca524 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -100,6 +100,8 @@ 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 for confirmation with "Is this ok?" before starting play +tty: responding with or duing role, race, &c selection + behaved same as to quit; now it will pick [random] instead unix/X11: in top level Makefile, some commented out definitions of VARDATND misspelled pilemark.xbm (as pilemark.xpm) unix/tty: fix compile warning about 'has_colors' for some configurations diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 96cc9b1ee..58dee65a3 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -441,7 +441,8 @@ makepicks: Strcpy(pbuf, "Pick a role or profession"); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); - choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; + choice = (n == 1) ? selected[0].item.a_int + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); @@ -526,7 +527,7 @@ makepicks: end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int - : ROLE_NONE; + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); @@ -615,7 +616,7 @@ makepicks: end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int - : ROLE_NONE; + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); @@ -700,7 +701,7 @@ makepicks: end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int - : ROLE_NONE; + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); From fbdeaae2861ec02d8b65034c84f1196ccd818b08 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 00:45:46 -0800 Subject: [PATCH 31/86] tribute: Equal Rites revisited The number of passages felt a little light, so split one of the long-ish ones into two. The punchline that now ends the first one was being watered down by continuing the text, and an interesting bit that was left out can be added to finish the second part. They both lose some context but I think they work ok separately. --- dat/tribute | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/dat/tribute b/dat/tribute index 6a7f63b31..53cfbd985 100644 --- a/dat/tribute +++ b/dat/tribute @@ -573,7 +573,7 @@ according its victims the dignity of hatred. It wouldn't even notice them. # # # -%title Equal Rites (9) +%title Equal Rites (10) # p. 118 (Signet edition; passage starts mid-sentence and ends mid-paragraph) %passage 1 [...] it is well known that a vital ingredient of success is not knowing @@ -650,11 +650,7 @@ rewrite them so that they don't apply to you. [Equal Rites, by Terry Pratchett] %e passage -# pp. 119-120 ("what is happening here?" actually omits "is" but -# must be a typo--fixed here to avoid bug reports; -# 'broomstick' is Esk's disguised wizard's staff; -# passage continues with questions about destination and -# why go overland when the river goes to the same place) +# pp. 119-120 (next passage is a direct continuation of this one) %passage 7 The town was smaller than Ohulan, and very different because it lay on the junction of three trade routes quite apart from the river itself. It was @@ -678,6 +674,13 @@ nevertheless, there were still people misguided enough to endure all this, plus long nights in uncomfortable surroundings, merely to get their hands on perfectly ordinary large boxes of jewels. + [Equal Rites, by Terry Pratchett] +%e passage +# pp. 120-121 (this passage is a direct continuation of preceding one; +# "I said, what is happening here?" actually omits "is" +# but must be a typo--fixed here to avoid bug reports; +# 'broomstick' is Esk's disguised wizard's staff) +%passage 8 So a town like Zemphis was the place where caravans split, mingled and came together again, as dozens of merchants and travellers banded together for protection against the socially disadvantaged on the trails ahead. @@ -704,10 +707,32 @@ He explained about the caravans. The child nodded. "Precisely." +"Where to?" + +"All sorts of places. Sto Lat, Pseudopolis... Ankh-Morpork, of course...." + +"But the river goes there," said Esk, reasonably. "Barges. The Zoons." + +"Ah, yes," said the merchant, "but they charge high prices and they can't +carry everything and, anyway, no one trusts them much." + +"But they're very honest!" + +"Huh, yes," he said. "But you know what they say: never trust an honest +man." He smiled knowingly. + +"Who says that?" + +"They do. You know. People," he said, a certain uneasiness entering his +voice. + +"Oh," said Esk. She thought about it. "They must be very silly," she said +primly. "Thank you, anyway." + [Equal Rites, by Terry Pratchett] %e passage # pp. 127-128 (this time broomstick is Granny's defective witch's broomstick) -%passage 8 +%passage 9 The broomstick lay between two trestles. Granny Weatherwax sat on a rock outcrop while a dwarf half her height, wearing an apron that was a mass of pockets, walked around the broom and occasionally poked it. @@ -759,7 +784,7 @@ back of his skull. [Equal Rites, by Terry Pratchett] %e passage # p. 185 (actually uses four periods to mark a sentence ending in a elipsis) -%passage 9 +%passage 10 There may be universes where librarianship is considered a peaceful sort of occupation, and where the risks are limited to large volumes falling off the shelves on to one's head, but the keeper of a /magic/ library is no job From 1bc05714b527737d671d065a2df5643c48a38e7a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 11:50:07 +0200 Subject: [PATCH 32/86] Fix bz66: Count number cannot be backspaced ... or at least partially fix it - ^H does now backspace. I can't be bothered to dive into the (n)curses raw-mode stuff. --- src/cmd.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 191ab71f3..dc1ae79df 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3874,6 +3874,7 @@ parse() #endif register int foo; boolean prezero = FALSE; + boolean backspaced = FALSE; multi = 0; context.move = 1; @@ -3885,13 +3886,23 @@ parse() if (!Cmd.num_pad || (foo = readchar()) == 'n') for (;;) { foo = readchar(); - if (foo >= '0' && foo <= '9') { - multi = 10 * multi + foo - '0'; + if ((foo >= '0' && foo <= '9') || (foo == '\b')) { + if (foo >= '0' && foo <= '9') + multi = 10 * multi + foo - '0'; + else { + multi = multi / 10; + backspaced = TRUE; + } if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT; - if (multi > 9) { + if (multi > 9 || backspaced) { clear_nhwindow(WIN_MESSAGE); - Sprintf(in_line, "Count: %d", multi); + if (backspaced && !multi) + Sprintf(in_line, "Count: "); + else { + Sprintf(in_line, "Count: %d", multi); + backspaced = FALSE; + } pline1(in_line); mark_synch(); } From 4c016853d47dcb9d1b51865de9dfcfa673f6e260 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 13:50:16 +0200 Subject: [PATCH 33/86] Unify getting a count into single function --- doc/fixes36.1 | 2 ++ include/extern.h | 1 + src/cmd.c | 85 +++++++++++++++++++++++++++++++----------------- src/invent.c | 59 ++++++++++++--------------------- 4 files changed, 80 insertions(+), 67 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index dee5ca524..05118711c 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -92,6 +92,8 @@ fix death reason when eating tainted glob of (not corpse) use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting +make commands that accept a count prefix for item selection + show "Count:" like command repeating does Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 5585692e0..52ffc37aa 100644 --- a/include/extern.h +++ b/include/extern.h @@ -204,6 +204,7 @@ E int FDECL(isok, (int, int)); E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int, int, int)); +E char FDECL(get_count, (char *, char, long, long *)); #ifdef HANGUPHANDLING E void FDECL(hangup, (int)); E void NDECL(end_of_input); diff --git a/src/cmd.c b/src/cmd.c index dc1ae79df..693666050 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3864,6 +3864,57 @@ int x, y, mod; return cmd; } +char +get_count(allowchars, inkey, max, count) +char *allowchars; +char inkey; +long max; +long *count; +{ + char qbuf[QBUFSZ]; + int key; + long cnt = 0; + boolean backspaced = FALSE; + char *ret; + for (;;) { + if (inkey) { + key = inkey; + inkey = '\0'; + } else + key = readchar(); + if (digit(key)) { + cnt = 10L * cnt + (long)(key - '0'); + } else if (key == '\b') { + cnt = cnt / 10; + backspaced = TRUE; + } else if (key == '\033') { + return '\033'; + } else if (allowchars) { + if (ret = index(allowchars, key)) { + *count = cnt; + return *ret; + } + } else { + *count = cnt; + return key; + } + if (max && (cnt > max)) + cnt = max; + if (cnt > 9 || backspaced) { + clear_nhwindow(WIN_MESSAGE); + if (backspaced && !cnt) + Sprintf(qbuf, "Count: "); + else { + Sprintf(qbuf, "Count: %d", cnt); + backspaced = FALSE; + } + pline1(qbuf); + mark_synch(); + } + } +} + + STATIC_OVL char * parse() { @@ -3883,35 +3934,11 @@ parse() #ifdef ALTMETA alt_esc = iflags.altmeta; /* readchar() hack */ #endif - if (!Cmd.num_pad || (foo = readchar()) == 'n') - for (;;) { - foo = readchar(); - if ((foo >= '0' && foo <= '9') || (foo == '\b')) { - if (foo >= '0' && foo <= '9') - multi = 10 * multi + foo - '0'; - else { - multi = multi / 10; - backspaced = TRUE; - } - if (multi < 0 || multi >= LARGEST_INT) - multi = LARGEST_INT; - if (multi > 9 || backspaced) { - clear_nhwindow(WIN_MESSAGE); - if (backspaced && !multi) - Sprintf(in_line, "Count: "); - else { - Sprintf(in_line, "Count: %d", multi); - backspaced = FALSE; - } - pline1(in_line); - mark_synch(); - } - last_multi = multi; - if (!multi && foo == '0') - prezero = TRUE; - } else - break; /* not a digit */ - } + if (!Cmd.num_pad || (foo = readchar()) == 'n') { + long tmpmulti = multi; + foo = get_count(NULL, '\0', LARGEST_INT, &tmpmulti); + last_multi = multi = tmpmulti; + } #ifdef ALTMETA alt_esc = FALSE; /* readchar() reset */ #endif diff --git a/src/invent.c b/src/invent.c index 0dd93861c..8b5a10a29 100644 --- a/src/invent.c +++ b/src/invent.c @@ -970,8 +970,8 @@ register const char *let, *word; boolean allownone = FALSE; boolean useboulder = FALSE; xchar foox = 0; - long cnt, prevcnt; - boolean prezero; + long cnt; + boolean cntgiven = FALSE; long dummymask; if (*let == ALLOW_COUNT) @@ -1163,9 +1163,7 @@ register const char *let, *word; } for (;;) { cnt = 0; - if (allowcnt == 2) - allowcnt = 1; /* abort previous count */ - prezero = FALSE; + cntgiven = FALSE; if (!buf[0]) { Sprintf(qbuf, "What do you want to %s? [*]", word); } else { @@ -1175,28 +1173,17 @@ register const char *let, *word; ilet = readchar(); else ilet = yn_function(qbuf, (char *) 0, '\0'); - if (digit(ilet) && !allowcnt) { - pline("No count allowed with this command."); - continue; - } - if (ilet == '0') - prezero = TRUE; - while (digit(ilet)) { - if (ilet != '?' && ilet != '*') - savech(ilet); - /* accumulate unless cnt has overflowed */ - if (allowcnt < 3) { - prevcnt = cnt; - cnt = 10L * cnt + (long) (ilet - '0'); - /* signal presence of cnt */ - allowcnt = (cnt >= prevcnt) ? 2 : 3; + if (digit(ilet)) { + long tmpcnt = 0; + if (!allowcnt) { + pline("No count allowed with this command."); + continue; + } + ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt); + if (tmpcnt) { + cnt = tmpcnt; + cntgiven = TRUE; } - ilet = readchar(); - } - if (allowcnt == 3) { - /* overflow detected; force cnt to be invalid */ - cnt = -1L; - allowcnt = 2; } if (index(quitchars, ilet)) { if (flags.verbose) @@ -1237,9 +1224,7 @@ register const char *let, *word; continue; if (allowcnt && ctmp >= 0) { cnt = ctmp; - if (!cnt) - prezero = TRUE; - allowcnt = 2; + cntgiven = TRUE; } if (ilet == '\033') { if (flags.verbose) @@ -1267,23 +1252,21 @@ register const char *let, *word; * to your money supply. The LRS is the tax bureau * from Larn. */ - if (allowcnt == 2 && cnt <= 0) { - if (cnt < 0 || !prezero) + if (cntgiven && cnt <= 0) { + if (cnt < 0) pline_The( "LRS would be very interested to know you have that much."); return (struct obj *) 0; } } - if (allowcnt == 2 && !strcmp(word, "throw")) { + if (cntgiven && !strcmp(word, "throw")) { /* permit counts for throwing gold, but don't accept * counts for other things since the throw code will * split off a single item anyway */ - if (ilet != def_oc_syms[COIN_CLASS].sym - && !(otmp && otmp->oclass == COIN_CLASS)) - allowcnt = 1; - if (cnt == 0 && prezero) + if (cnt == 0) return (struct obj *) 0; - if (cnt > 1) { + if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym + && !(otmp && otmp->oclass == COIN_CLASS))) { You("can only throw one item at a time."); continue; } @@ -1311,7 +1294,7 @@ register const char *let, *word; silly_thing(word, otmp); return (struct obj *) 0; } - if (allowcnt == 2) { /* cnt given */ + if (cntgiven) { if (cnt == 0) return (struct obj *) 0; if (cnt != otmp->quan) { From 5ccfd34328fa29a35d2c7cd8931679899ed563b3 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 14:05:24 +0200 Subject: [PATCH 34/86] Allow picking a used inventory letter from menu when #adjusting --- doc/fixes36.1 | 1 + src/invent.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 05118711c..7fd5aec74 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -94,6 +94,7 @@ fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting make commands that accept a count prefix for item selection show "Count:" like command repeating does +allow picking a used inventory letter from menu when #adjusting Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index 8b5a10a29..a79c7d46b 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2182,7 +2182,7 @@ char avoidlet; } end_menu(win, "Inventory letters used:"); - n = select_menu(win, PICK_NONE, &selected); + n = select_menu(win, PICK_ONE, &selected); if (n > 0) { ret = selected[0].item.a_char; free((genericptr_t) selected); From 72f55fedb554102a7d8aacb2bb214972a810788c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 14:17:11 +0200 Subject: [PATCH 35/86] Zapping wand of opening at yourself, unlock carried boxes --- doc/fixes36.1 | 1 + src/zap.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 7fd5aec74..88bbeecb7 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -95,6 +95,7 @@ redraw map when hilite_pile is toggled to display the highlighting make commands that accept a count prefix for item selection show "Count:" like command repeating does allow picking a used inventory letter from menu when #adjusting +zapping wand of opening at yourself, unlock carried boxes Platform- and/or Interface-Specific Fixes diff --git a/src/zap.c b/src/zap.c index 677921c2e..3295e690a 100644 --- a/src/zap.c +++ b/src/zap.c @@ -2368,7 +2368,13 @@ boolean ordinary; } if (u.utrap) { /* escape web or bear trap */ (void) openholdingtrap(&youmonst, &learn_it); - } else { /* trigger previously escaped trapdoor */ + } else { + struct obj *otmp; + /* unlock carried boxes */ + for (otmp = invent; otmp; otmp = otmp->nobj) + if (Is_box(otmp)) + (void) boxlock(otmp, obj); + /* trigger previously escaped trapdoor */ (void) openfallingtrap(&youmonst, TRUE, &learn_it); } break; From 237c4a2787119a5fc72741f650943923f7e4b12c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 15:33:36 +0200 Subject: [PATCH 36/86] Allow dissolving iron bars with potion of acid Force-fight iron bars with wielded potion of acid to dissolve them This change comes via UnNetHack by Patric Mueller. --- doc/fixes36.1 | 1 + include/extern.h | 3 ++- src/hack.c | 13 +++++++++++ src/mthrowu.c | 59 ++++++++++++++++++++++++++++++++++++------------ src/trap.c | 4 +++- src/zap.c | 1 + 6 files changed, 64 insertions(+), 17 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 88bbeecb7..292a9ff31 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -96,6 +96,7 @@ make commands that accept a count prefix for item selection show "Count:" like command repeating does allow picking a used inventory letter from menu when #adjusting zapping wand of opening at yourself, unlock carried boxes +dissolve iron bars by force-fighting with wielded potion of acid Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 52ffc37aa..ea89ad2ba 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1503,7 +1503,8 @@ E void FDECL(m_useupall, (struct monst *, struct obj *)); E void FDECL(m_useup, (struct monst *, struct obj *)); E void FDECL(m_throw, (struct monst *, int, int, int, int, int, struct obj *)); -E boolean FDECL(hits_bars, (struct obj **, int, int, int, int)); +E void FDECL(hit_bars, (struct obj **, int, int, int, int, boolean, boolean)); +E boolean FDECL(hits_bars, (struct obj **, int, int, int, int, int, int)); /* ### muse.c ### */ diff --git a/src/hack.c b/src/hack.c index 6305ad1e7..098546579 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1437,6 +1437,19 @@ domove() } } + if (context.forcefight && levl[x][y].typ == IRONBARS && uwep) { + struct obj *obj = uwep; + if (breaktest(obj)) { + if (obj->quan > 1L) + obj = splitobj(obj, 1L); + else + setuwep((struct obj *)0); + freeinv(obj); + } + hit_bars(&obj, u.ux, u.uy, x, y, TRUE, TRUE); + return; + } + /* specifying 'F' with no monster wastes a turn */ if (context.forcefight /* remembered an 'I' && didn't use a move command */ diff --git a/src/mthrowu.c b/src/mthrowu.c index b63a47900..54ef961fd 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -318,7 +318,9 @@ struct obj *obj; /* missile (or stack providing it) */ || 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, 0, 0))) { + && hits_bars(&singleobj, + bhitpos.x, bhitpos.y, + bhitpos.x + dx, bhitpos.y + dy, 0, 0))) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } @@ -455,7 +457,10 @@ struct obj *obj; /* missile (or stack providing it) */ || 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, !rn2(5), 0)) + && 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)) { if (singleobj) /* hits_bars might have destroyed it */ @@ -831,11 +836,45 @@ int type; return (struct obj *) 0; } +void +hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent) +struct obj **objp; /* *objp will be set to NULL if object breaks */ +int objx, objy, barsx, barsy; +boolean your_fault, from_invent; +{ + struct obj *otmp = *objp; + int obj_type = otmp->otyp; + boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0; + + if (your_fault + ? hero_breaks(otmp, objx, objy, from_invent) + : breaks(otmp, objx, objy)) { + *objp = 0; /* object is now gone */ + /* breakage makes its own noises */ + if (obj_type == POT_ACID) { + if (cansee(barsx, barsy) && !unbreakable) + pline_The("iron bars are dissolved!"); + else + You_hear(Hallucination ? "angry snakes!" : "a hissing noise."); + if (!unbreakable) + dissolve_bars(barsx, barsy); + } + } + else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) + pline("Whang!"); + else if (otmp->oclass == COIN_CLASS + || objects[obj_type].oc_material == GOLD + || objects[obj_type].oc_material == SILVER) + pline("Clink!"); + else + pline("Clonk!"); +} + /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */ boolean -hits_bars(obj_p, x, y, always_hit, whodidit) +hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit) struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */ -int x, y; +int x, y, barsx, barsy; int always_hit; /* caller can force a hit for items which would fit through */ int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */ { @@ -885,17 +924,7 @@ int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */ } if (hits && whodidit != -1) { - if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y)) - *obj_p = otmp = 0; /* object is now gone */ - /* breakage makes its own noises */ - else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) - pline("Whang!"); - else if (otmp->oclass == COIN_CLASS - || objects[obj_type].oc_material == GOLD - || objects[obj_type].oc_material == SILVER) - pline("Clink!"); - else - pline("Clonk!"); + hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE); } return hits; diff --git a/src/trap.c b/src/trap.c index 7f9a1ea7d..71700c6c8 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1889,7 +1889,9 @@ int style; if (dist > 0 && isok(bhitpos.x + dx, bhitpos.y + dy) && levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) { x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */ - if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) { + if (hits_bars(&singleobj, + x2, y2, x2+dx, y2+dy, + !rn2(20), 0)) { if (!singleobj) { used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); diff --git a/src/zap.c b/src/zap.c index 3295e690a..1aaa3d14e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3103,6 +3103,7 @@ struct obj **pobj; /* object tossed/used, set to NULL /* iron bars will block anything big enough */ if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) && typ == IRONBARS && hits_bars(pobj, x - ddx, y - ddy, + bhitpos.x, bhitpos.y, point_blank ? 0 : !rn2(5), 1)) { /* caveat: obj might now be null... */ obj = *pobj; From da0e660110c85d2bfce393abb4ec71d836ed6504 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 16:05:40 +0200 Subject: [PATCH 37/86] Poison breath leaves a trail of poison gas clouds Original patch by L --- doc/fixes36.1 | 1 + src/zap.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 292a9ff31..e957b09fd 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -97,6 +97,7 @@ make commands that accept a count prefix for item selection allow picking a used inventory letter from menu when #adjusting zapping wand of opening at yourself, unlock carried boxes dissolve iron bars by force-fighting with wielded potion of acid +poison breath leaves a trail of poison gas Platform- and/or Interface-Specific Fixes diff --git a/src/zap.c b/src/zap.c index 1aaa3d14e..0749c8dbf 100644 --- a/src/zap.c +++ b/src/zap.c @@ -4312,6 +4312,10 @@ short exploding_wand_typ; } break; /* ZT_COLD */ + case ZT_POISON_GAS: + (void) create_gas_cloud(x, y, 1, 8); + break; + case ZT_ACID: if (lev->typ == IRONBARS) { if ((lev->wall_info & W_NONDIGGABLE) != 0) { From c740425a90192595be4c81177e9db62e3a333bbf Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 16:23:48 +0200 Subject: [PATCH 38/86] Use define for iron ball weight increment --- include/hack.h | 3 +++ src/objnam.c | 2 +- src/read.c | 2 +- src/weapon.c | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/hack.h b/include/hack.h index 2eae9e6ba..816b7fee0 100644 --- a/include/hack.h +++ b/include/hack.h @@ -29,6 +29,9 @@ #define EXT_ENCUMBER 4 /* Overtaxed */ #define OVERLOADED 5 /* Overloaded */ +/* weight increment of heavy iron ball */ +#define IRON_BALL_W_INCR 160 + /* hunger states - see hu_stat in eat.c */ #define SATIATED 0 #define NOT_HUNGRY 1 diff --git a/src/objnam.c b/src/objnam.c index 5dc1e8c2e..8e98e07b8 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3533,7 +3533,7 @@ typfnd: } otmp->owt = weight(otmp); if (very && otmp->otyp == HEAVY_IRON_BALL) - otmp->owt += 160; + otmp->owt += IRON_BALL_W_INCR; return otmp; } diff --git a/src/read.c b/src/read.c index 94619ba11..4ba274146 100644 --- a/src/read.c +++ b/src/read.c @@ -2271,7 +2271,7 @@ struct obj *sobj; You("are being punished for your misbehavior!"); if (Punished) { Your("iron ball gets heavier."); - uball->owt += 160 * (1 + sobj->cursed); + uball->owt += IRON_BALL_W_INCR * (1 + sobj->cursed); return; } if (amorphous(youmonst.data) || is_whirly(youmonst.data) diff --git a/src/weapon.c b/src/weapon.c index cc14f35ec..cdbd440db 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -304,12 +304,12 @@ struct monst *mon; if (ptr == &mons[PM_SHADE] && !shade_glare(otmp)) tmp = 0; - /* "very heavy iron ball"; weight increase is in increments of 160 */ + /* "very heavy iron ball"; weight increase is in increments */ if (otyp == HEAVY_IRON_BALL && tmp > 0) { int wt = (int) objects[HEAVY_IRON_BALL].oc_weight; if ((int) otmp->owt > wt) { - wt = ((int) otmp->owt - wt) / 160; + wt = ((int) otmp->owt - wt) / IRON_BALL_W_INCR; tmp += rnd(4 * wt); if (tmp > 25) tmp = 25; /* objects[].oc_wldam */ From c2ceb88d3c5682974bc2b866b6cbec1a1fdd3578 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 17:28:41 +0200 Subject: [PATCH 39/86] Make vault guard accept names starting with number Fix via Dynahack by Tung Nguyen --- doc/fixes36.1 | 1 + src/vault.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index e957b09fd..6bdc85bad 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -98,6 +98,7 @@ allow picking a used inventory letter from menu when #adjusting zapping wand of opening at yourself, unlock carried boxes dissolve iron bars by force-fighting with wielded potion of acid poison breath leaves a trail of poison gas +make vault guard accept names starting with number Platform- and/or Interface-Specific Fixes diff --git a/src/vault.c b/src/vault.c index 5b73dadc5..52ca97660 100644 --- a/src/vault.c +++ b/src/vault.c @@ -376,7 +376,7 @@ invault() do { getlin("\"Hello stranger, who are you?\" -", buf); (void) mungspaces(buf); - } while (!letter(buf[0]) && --trycount > 0); + } while (!buf[0] && --trycount > 0); if (u.ualign.type == A_LAWFUL /* ignore trailing text, in case player includes rank */ From 785aba242a6340511765eeef580c9d40c34dfbac Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:15:04 +0200 Subject: [PATCH 40/86] Fix the mtrack memset --- src/dog.c | 2 +- src/monmove.c | 2 +- src/teleport.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dog.c b/src/dog.c index 361c7de02..a5f8a5a75 100644 --- a/src/dog.c +++ b/src/dog.c @@ -325,7 +325,7 @@ boolean with_you; xyflags = mtmp->mtrack[0].y; xlocale = mtmp->mtrack[1].x; ylocale = mtmp->mtrack[1].y; - memset(mtmp->mtrack, MTSZ, sizeof(coord)); + memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); if (mtmp == u.usteed) return; /* don't place steed on the map */ diff --git a/src/monmove.c b/src/monmove.c index cae22b8b5..86432a6c5 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -272,7 +272,7 @@ boolean fleemsg; mtmp->mflee = 1; } /* ignore recently-stepped spaces when made to flee */ - memset(mtmp->mtrack, MTSZ, sizeof(coord)); + memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); } STATIC_OVL void diff --git a/src/teleport.c b/src/teleport.c index 47780e7da..43e97da63 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -980,7 +980,7 @@ register int x, y; } } - memset(mtmp->mtrack, MTSZ, sizeof(coord)); + memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); place_monster(mtmp, x, y); /* put monster down */ update_monster_region(mtmp); From 0a2550259319b65fb825bb4d8aa7f95a3e545593 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:25:17 +0200 Subject: [PATCH 41/86] Fix weight of containers in lev_comp --- doc/fixes36.1 | 1 + src/sp_lev.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 6bdc85bad..8b999752b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -99,6 +99,7 @@ zapping wand of opening at yourself, unlock carried boxes dissolve iron bars by force-fighting with wielded potion of acid poison breath leaves a trail of poison gas make vault guard accept names starting with number +fix weight of containers in special levels Platform- and/or Interface-Specific Fixes diff --git a/src/sp_lev.c b/src/sp_lev.c index 79a3bbcc8..c4428d7ad 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1873,11 +1873,12 @@ struct mkroom *croom; } } } else { + struct obj *cobj = container_obj[container_idx - 1]; remove_object(otmp); - if (container_obj[container_idx - 1]) - (void) add_to_container(container_obj[container_idx - 1], - otmp); - else { + if (cobj) { + (void) add_to_container(cobj, otmp); + cobj->owt = weight(cobj); + } else { obj_extract_self(otmp); obfree(otmp, NULL); return; From caf872be05cb6a6d7d176af9902cc3e1f381c95c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:40:41 +0200 Subject: [PATCH 42/86] Allow knife and stiletto as possible tin opening tools Via Dynahack, original idea from K-mod by Karadoc. --- doc/fixes36.1 | 1 + src/eat.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 8b999752b..922eecf7b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -100,6 +100,7 @@ dissolve iron bars by force-fighting with wielded potion of acid poison breath leaves a trail of poison gas make vault guard accept names starting with number fix weight of containers in special levels +allow knife and stiletto as possible tin opening tools Platform- and/or Interface-Specific Fixes diff --git a/src/eat.c b/src/eat.c index d041976dd..7591b9cc3 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1431,6 +1431,8 @@ struct obj *otmp; case ELVEN_DAGGER: case ORCISH_DAGGER: case ATHAME: + case KNIFE: + case STILETTO: case CRYSKNIFE: tmp = 3; break; From c8d0b04c749babf06d9a8fa42dbceb3c40c55212 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:54:21 +0200 Subject: [PATCH 43/86] Make the raven medusa level shortsighted This prevents all of the ravens mobbing the player immediately. Change via Dynahack by Tung Nguyen --- dat/medusa.des | 2 +- doc/fixes36.1 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dat/medusa.des b/dat/medusa.des index 3e1a70521..b449a29e2 100644 --- a/dat/medusa.des +++ b/dat/medusa.des @@ -218,7 +218,7 @@ MONSTER:random,random LEVEL:"medusa-3" -FLAGS: noteleport,mazelevel +FLAGS: noteleport,mazelevel,shortsighted INIT_MAP:solidfill,' ' GEOMETRY:center,center # diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 922eecf7b..9df0bdc0a 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -101,6 +101,7 @@ poison breath leaves a trail of poison gas make vault guard accept names starting with number fix weight of containers in special levels allow knife and stiletto as possible tin opening tools +make the raven medusa level shortsighted Platform- and/or Interface-Specific Fixes From 50359a35525bcaa534a07cf605ee761a40ff2fad Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 19:48:46 +0200 Subject: [PATCH 44/86] Fix possible lev_comp segfault when map was too tall --- doc/fixes36.1 | 1 + util/lev_main.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 9df0bdc0a..97fc2b360 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -102,6 +102,7 @@ make vault guard accept names starting with number fix weight of containers in special levels allow knife and stiletto as possible tin opening tools make the raven medusa level shortsighted +fix possible segfault in lev_comp when map was too tall Platform- and/or Interface-Specific Fixes diff --git a/util/lev_main.c b/util/lev_main.c index d3350e178..c95441bce 100644 --- a/util/lev_main.c +++ b/util/lev_main.c @@ -1351,7 +1351,7 @@ sp_lev *sp; register char *s1, *s2; int max_len = 0; int max_hig = 0; - char *tmpmap[ROWNO]; + char *tmpmap[MAP_Y_LIM+1]; int dx, dy; char *mbuf; @@ -1378,6 +1378,8 @@ sp_lev *sp; /* Then parse it now */ while (map && *map) { + if (max_hig > MAP_Y_LIM) + break; tmpmap[max_hig] = (char *) alloc(max_len); s1 = index(map, '\n'); if (s1) { From 5d1281c9ac38c30eb68e5e0e7df3182a04943e5a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 21:42:45 +0200 Subject: [PATCH 45/86] Make getpos monster targeting use glyph lookup --- src/do_name.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 567720e67..2341adb0e 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -244,24 +244,28 @@ const char *goal; goto nxtc; } else if (c == 'm' || c == 'M') { if (!monarr) { - struct monst *mtmp; + int x,y,s; moncount = 0; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (canspotmon(mtmp) - && (mtmp->mx != u.ux || mtmp->my != u.uy)) - moncount++; - } - /* moncount + 1: always allocate a non-zero amount */ - monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); - monidx = 0; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (canspotmon(mtmp) - && (mtmp->mx != u.ux || mtmp->my != u.uy)) { - monarr[monidx].x = mtmp->mx; - monarr[monidx].y = mtmp->my; - monidx++; + for (s = 0; s < 2; s++) { + if (s) { + /* moncount + 1: always allocate a non-zero amount */ + monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); + monidx = 0; } + if (!s || s && moncount) + for (x = 0; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) + if (glyph_is_monster(glyph_at(x,y)) + && !(x == u.ux && y == u.uy)) { + if (!s) + moncount++; + else { + monarr[monidx].x = x; + monarr[monidx].y = y; + monidx++; + } + } } qsort(monarr, moncount, sizeof (coord), cmp_coord_distu); /* ready for first increment/decrement to change to zero */ From c8cd550a5ae1350bbf4576a9c422c57e2d2eefca Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 15:37:46 -0800 Subject: [PATCH 46/86] get_count() cleanup Fix several warnings. Accept ASCII RUBOUT (aka DELETE) in addition to backspace. [Should use erase_char (and add support for kill_char) but that means pushing get_count() into the interface code.] Guard against user causing the count to wrap if someone ever adds a call to get_count() which doesn't specifying a maximum value. --- include/extern.h | 10 +++++----- src/cmd.c | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/include/extern.h b/include/extern.h index ea89ad2ba..3e58ee565 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1451955077 2016/01/05 00:51:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.530 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1452123455 2016/01/06 23:37:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.535 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -204,7 +204,7 @@ E int FDECL(isok, (int, int)); E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int, int, int)); -E char FDECL(get_count, (char *, char, long, long *)); +E char FDECL(get_count, (char *, CHAR_P, long, long *)); #ifdef HANGUPHANDLING E void FDECL(hangup, (int)); E void NDECL(end_of_input); @@ -1501,9 +1501,9 @@ E boolean FDECL(lined_up, (struct monst *)); E struct obj *FDECL(m_carrying, (struct monst *, int)); E void FDECL(m_useupall, (struct monst *, struct obj *)); E void FDECL(m_useup, (struct monst *, struct obj *)); -E void FDECL(m_throw, - (struct monst *, int, int, int, int, int, struct obj *)); -E void FDECL(hit_bars, (struct obj **, int, int, int, int, boolean, boolean)); +E void FDECL(m_throw, (struct monst *, int, int, int, int, int, struct obj *)); +E void FDECL(hit_bars, (struct obj **, int, int, int, int, + BOOLEAN_P, BOOLEAN_P)); E boolean FDECL(hits_bars, (struct obj **, int, int, int, int, int, int)); /* ### muse.c ### */ diff --git a/src/cmd.c b/src/cmd.c index 693666050..162234a76 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1451082253 2015/12/25 22:24:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.212 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1452123457 2016/01/06 23:37:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.216 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3865,53 +3865,56 @@ int x, y, mod; } char -get_count(allowchars, inkey, max, count) +get_count(allowchars, inkey, maxcount, count) char *allowchars; char inkey; -long max; +long maxcount; long *count; { char qbuf[QBUFSZ]; int key; - long cnt = 0; + long cnt = 0L; boolean backspaced = FALSE; - char *ret; + /* this should be done in port code so that we have erase_char + and kill_char available; we can at least fake erase_char */ +#define STANDBY_erase_char '\177' + for (;;) { if (inkey) { key = inkey; inkey = '\0'; } else key = readchar(); + if (digit(key)) { - cnt = 10L * cnt + (long)(key - '0'); - } else if (key == '\b') { + cnt = 10L * cnt + (long) (key - '0'); + if (cnt < 0) + cnt = 0; + else if (maxcount > 0 && cnt > maxcount) + cnt = maxcount; + } else if (key == '\b' || key == STANDBY_erase_char) { cnt = cnt / 10; backspaced = TRUE; } else if (key == '\033') { - return '\033'; - } else if (allowchars) { - if (ret = index(allowchars, key)) { - *count = cnt; - return *ret; - } - } else { + break; + } else if (!allowchars || index(allowchars, key)) { *count = cnt; - return key; + break; } - if (max && (cnt > max)) - cnt = max; + if (cnt > 9 || backspaced) { clear_nhwindow(WIN_MESSAGE); - if (backspaced && !cnt) + if (backspaced && !cnt) { Sprintf(qbuf, "Count: "); - else { - Sprintf(qbuf, "Count: %d", cnt); + } else { + Sprintf(qbuf, "Count: %ld", cnt); backspaced = FALSE; } pline1(qbuf); mark_synch(); } } + return key; } @@ -3925,7 +3928,6 @@ parse() #endif register int foo; boolean prezero = FALSE; - boolean backspaced = FALSE; multi = 0; context.move = 1; @@ -3936,6 +3938,7 @@ parse() #endif if (!Cmd.num_pad || (foo = readchar()) == 'n') { long tmpmulti = multi; + foo = get_count(NULL, '\0', LARGEST_INT, &tmpmulti); last_multi = multi = tmpmulti; } From 22685763d1a7f2a4d645d61e35028e56c36e8cfe Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 16:47:30 -0800 Subject: [PATCH 47/86] getpos() for objects Extend the 'm' and 'M' functionality (move cursor to nearest monster or farthest monster, respectively, then to next nearest/next farthest when used successively) to 'o' and 'O' for objects. 'M' was picking the wrong monster (nearest) on first use; now fixed. Hero is now included in the monster list, and will be the last one reached if you cycle all the way through in either direction. (Makes it easier to tell that you have actually been all the way through. Unfortunately, objects don't have any seen-'em-all indicator. Perhaps the hero's coordinates should go on that list too?) --- doc/fixes36.1 | 15 ++++--- src/do_name.c | 117 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 97fc2b360..2602460c0 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -87,20 +87,14 @@ requiver pickup_thrown objects if quiver is empty make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact -allow moving cursor to monsters with 'm' and 'M' when asked for map location fix death reason when eating tainted glob of (not corpse) use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting make commands that accept a count prefix for item selection show "Count:" like command repeating does -allow picking a used inventory letter from menu when #adjusting -zapping wand of opening at yourself, unlock carried boxes -dissolve iron bars by force-fighting with wielded potion of acid -poison breath leaves a trail of poison gas make vault guard accept names starting with number fix weight of containers in special levels -allow knife and stiletto as possible tin opening tools make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall @@ -134,10 +128,17 @@ General New Features -------------------- naming Sting or Orcrist now breaks illiterate conduct different feedback for reading a scroll of mail created by writing with marker -wizard mode #wizintrinsic reading non-cursed scroll of enchant weapon uncurses welded tin opener if hero has no jumping ability but knows the jumping spell, the #jump command will attempt to cast the spell +allow moving cursor to monsters with 'm' (nearest first) and 'M' (furthest + first) when asked for map location, or to objects with 'o' and 'O' +allow picking a used inventory letter from menu when #adjusting +zapping wand of opening at yourself, unlock carried boxes +dissolve iron bars by force-fighting with wielded potion of acid +poison breath leaves a trail of poison gas +allow knife and stiletto as possible tin opening tools +wizard mode #wizintrinsic command additional tribute passages for The Colour of Magic, The Light Fantastic, Equal Rites, Snuff, and Raising Steam compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use diff --git a/src/do_name.c b/src/do_name.c index 2341adb0e..da48c07dc 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -8,6 +8,7 @@ STATIC_DCL char *NDECL(nextmbuf); STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *)); STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *)); +STATIC_OVL void FDECL(gather_locs, (coord **, int *, BOOLEAN_P)); STATIC_DCL void NDECL(do_mname); STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *)); STATIC_DCL void FDECL(do_oname, (struct obj *)); @@ -58,6 +59,7 @@ const char *goal; putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); putstr(tmpwin, 0, "Use @ to move the cursor on yourself."); putstr(tmpwin, 0, "Use m or M to move the cursor to next monster."); + putstr(tmpwin, 0, "Use o or O to move the cursor to next object."); if (getpos_hilitefunc) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); @@ -93,6 +95,61 @@ const void *b; return dist_1 - dist_2; } +/* gather locations for monsters or objects shown on the map */ +STATIC_OVL void +gather_locs(arr_p, cnt_p, do_mons) +coord **arr_p; +int *cnt_p; +boolean do_mons; +{ + int x, y, pass, glyph, idx; + + *cnt_p = idx = 0; + for (pass = 0; pass < 2; pass++) { + if (pass) { + /* *cnt_p + 1: always allocate a non-zero amount */ + *arr_p = (coord *) alloc(sizeof (coord) * (*cnt_p + 1)); + if (!*cnt_p) { + /* needed for caller's mon[0].x,.y==u.ux,.uy check */ + (*arr_p)[0].x = (*arr_p)[0].y = 0; + break; + } + } + for (x = 1; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) { + glyph = glyph_at(x, y); + if (do_mons) { + /* unlike '/M', this skips monsters revealed by + * warning glyphs and remembered invisible ones; + * TODO: skip worm tails + */ + if (glyph_is_monster(glyph)) { + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; + } + } + } else { /* objects */ + /* TODO: skip boulders and rocks */ + if (glyph_is_object(glyph)) { + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; + } + } + } + } + } /* pass */ + if (*cnt_p) + qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu); +} + int getpos(ccp, force, goal) coord *ccp; @@ -107,9 +164,8 @@ const char *goal; static const char pick_chars[] = ".,;:"; const char *cp; boolean hilite_state = FALSE; - coord *monarr = NULL; - int moncount = 0; - int monidx = 0; + coord *monarr = (coord *) 0, *objarr = (coord *) 0; + int moncount = 0, monidx = 0, objcount = 0, objidx = 0; if (!goal) goal = "desired location"; @@ -244,32 +300,15 @@ const char *goal; goto nxtc; } else if (c == 'm' || c == 'M') { if (!monarr) { - int x,y,s; - - moncount = 0; - for (s = 0; s < 2; s++) { - if (s) { - /* moncount + 1: always allocate a non-zero amount */ - monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); - monidx = 0; - } - if (!s || s && moncount) - for (x = 0; x < COLNO; x++) - for (y = 0; y < ROWNO; y++) - if (glyph_is_monster(glyph_at(x,y)) - && !(x == u.ux && y == u.uy)) { - if (!s) - moncount++; - else { - monarr[monidx].x = x; - monarr[monidx].y = y; - monidx++; - } - } - } - qsort(monarr, moncount, sizeof (coord), cmp_coord_distu); - /* ready for first increment/decrement to change to zero */ - monidx = (c == 'm') ? -1 : 1; + gather_locs(&monarr, &moncount, TRUE); + /* when hero is first element (always, unless unseen), + we want first increment to reach 1 (nearest aside + from hero) or first decrement to reach moncount-1 + (farthest); if hero is not first element, we want + first increment to end up with 0 (nearest monster), + first decrement should still choose moncount-1 */ + monidx = (monarr[0].x == u.ux && monarr[0].y == u.uy) ? 0 + : (c == 'm') ? -1 : 0; } if (moncount) { if (c == 'm') { @@ -282,6 +321,24 @@ const char *goal; cy = monarr[monidx].y; goto nxtc; } + } else if (c == 'o' || c == 'O') { + if (!objarr) { + gather_locs(&objarr, &objcount, FALSE); + /* ready for first increment to change to zero + or first decrement to change to objcount-1 */ + objidx = (c == 'o') ? -1 : 0; + } + if (objcount) { + if (c == 'o') { + objidx = (objidx + 1) % objcount; + } else { + if (--objidx < 0) + objidx = objcount - 1; + } + cx = objarr[objidx].x; + cy = objarr[objidx].y; + goto nxtc; + } } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; @@ -375,6 +432,8 @@ const char *goal; ccp->y = cy; if (monarr) free((genericptr_t) monarr); + if (objarr) + free((genericptr_t) objarr); getpos_hilitefunc = (void FDECL((*), (int))) 0; return result; } From d8591be858cefceef4db2c159dba14efe9d4c28f Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 17:57:39 -0800 Subject: [PATCH 48/86] fix #4138 - 'text bug' for freezing moat Freezing a moat--unlike other types of water--substitutes the type of water (because that isn't "moat" for Medusa's level) in the freeze message but was doing so after changing the affected terrain to ICE, yielding "The ice is bridged with ice." --- doc/fixes36.1 | 1 + src/zap.c | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 2602460c0..12386fc24 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -97,6 +97,7 @@ make vault guard accept names starting with number fix weight of containers in special levels make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall +fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea Platform- and/or Interface-Specific Fixes diff --git a/src/zap.c b/src/zap.c index 0749c8dbf..6a695fbac 100644 --- a/src/zap.c +++ b/src/zap.c @@ -4234,8 +4234,8 @@ short exploding_wand_typ; case ZT_COLD: if (is_pool(x, y) || is_lava(x, y)) { - boolean lava = is_lava(x, y); - boolean moat = is_moat(x, y); + boolean lava = is_lava(x, y), + moat = is_moat(x, y); if (lev->typ == WATER) { /* For now, don't let WATER freeze. */ @@ -4245,23 +4245,25 @@ short exploding_wand_typ; You_hear("a soft crackling."); rangemod -= 1000; /* stop */ } else { + char buf[BUFSZ]; + + Strcpy(buf, waterbody_name(x, y)); /* for MOAT */ rangemod -= 3; if (lev->typ == DRAWBRIDGE_UP) { lev->drawbridgemask &= ~DB_UNDER; /* clear lava */ lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE); } else { if (!lava) - lev->icedpool = - (lev->typ == POOL ? ICED_POOL : ICED_MOAT); - lev->typ = (lava ? ROOM : ICE); + lev->icedpool = (lev->typ == POOL) ? ICED_POOL + : ICED_MOAT; + lev->typ = lava ? ROOM : ICE; } bury_objs(x, y); if (see_it) { if (lava) Norep("The lava cools and solidifies."); else if (moat) - Norep("The %s is bridged with ice!", - waterbody_name(x, y)); + Norep("The %s is bridged with ice!", buf); else Norep("The water freezes."); newsym(x, y); From b48673425eb3c5a954a59f62f3b6de690f476bee Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Jan 2016 21:04:05 -0500 Subject: [PATCH 49/86] vault Deaf bits --- src/vault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vault.c b/src/vault.c index 365f06cc9..18c1d9a16 100644 --- a/src/vault.c +++ b/src/vault.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vault.c $NHDT-Date: 1451962301 2016/01/05 02:51:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.40 $ */ +/* NetHack 3.6 vault.c $NHDT-Date: 1452132199 2016/01/07 02:03:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -377,7 +377,7 @@ invault() } trycount = 5; do { - getlin(Deaf ? "You are required to sign in with your name. -" : + getlin(Deaf ? "You are required to supply your name. -" : "\"Hello stranger, who are you?\" -", buf); (void) mungspaces(buf); } while (!buf[0] && --trycount > 0); From 9fae6217786305dd4c5fdd7961c9f4674fdac625 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 7 Jan 2016 01:53:06 -0800 Subject: [PATCH 50/86] fix #H4181 - strange death messages "Petrified by , while getting stoned." -- multi_reason "while getting stoned" explains why no last-second recovery could be made, but doesn't explain how the petrification happened, so suppress it. "Died of starvation, while fainted from lack of food." -- nethack does not display this; presumeably the IRC death notices for NAO are generated from xlogfile entries. Change 'while fainted from lack of food' to 'while fainted' at time of death if reason for death is starvation. The longer version is accurate but sounds fairly silly. When starvation is set in motion, set it up before checking whether the initial faint triggers falling on a wielded cockatrice corpse, so that fainting isn't applied after recovery in case of life-saving. --- doc/fixes36.1 | 1 + src/eat.c | 4 ++-- src/end.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 12386fc24..b2c3197ca 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -88,6 +88,7 @@ make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact fix death reason when eating tainted glob of (not corpse) +fix death reason when petrified (avoid redundant 'while getting stoned') use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting diff --git a/src/eat.c b/src/eat.c index 7591b9cc3..13a394405 100644 --- a/src/eat.c +++ b/src/eat.c @@ -2838,14 +2838,14 @@ boolean incr; /* stop what you're doing, then faint */ stop_occupation(); You("faint from lack of food."); - if (!Levitation) - selftouch("Falling, you"); incr_itimeout(&HDeaf, duration); nomul(-duration); multi_reason = "fainted from lack of food"; nomovemsg = "You regain consciousness."; afternmv = unfaint; newhs = FAINTED; + if (!Levitation) + selftouch("Falling, you"); } } else if (u.uhunger < -(int) (200 + 20 * ACURR(A_CON))) { u.uhs = STARVED; diff --git a/src/end.c b/src/end.c index 5e5231856..7e53467e7 100644 --- a/src/end.c +++ b/src/end.c @@ -503,6 +503,42 @@ int how; return; } +/* some special cases for overriding while-helpless reason */ +static const struct { + int why, unmulti; + const char *exclude, *include; +} death_fixups[] = { + /* "petrified by , while getting stoned" -- "while getting stoned" + prevented any last-second recovery, but it was not the cause of + "petrified by " */ + { STONING, 1, "getting stoned", (char *) 0 }, + /* "died of starvation, while fainted from lack of food" is accurate + but sounds a fairly silly (and doesn't actually appear unless you + splice together death and while-helpless from xlogfile) */ + { STARVING, 0, "fainted from lack of food", "fainted" }, +}; + +/* clear away while-helpless when the cause of death caused that + helplessness (ie, "petrified by while getting stoned") */ +STATIC_DCL void +fixup_death(how) +int how; +{ + int i; + + for (i = 0; i < SIZE(death_fixups); ++i) + if (death_fixups[i].why == how + && !strcmp(death_fixups[i].exclude, multi_reason)) { + if (death_fixups[i].include) /* substitute an alternate reason */ + multi_reason = death_fixups[i].include; + else /* remove the helplessness reason */ + multi_reason = (char *) 0; + if (death_fixups[i].unmulti) /* possibly hide helplessness */ + multi = 0L; + break; + } +} + #if defined(WIN32) && !defined(SYSCF) #define NOTIFY_NETHACK_BUGS #endif @@ -1002,6 +1038,8 @@ int how; if (how == ESCAPED || how == PANICKED) killer.format = NO_KILLER_PREFIX; + fixup_death(how); /* actually, fixup multi_reason */ + if (how != PANICKED) { /* these affect score and/or bones, but avoid them during panic */ taken = paybill((how == ESCAPED) ? -1 : (how != QUIT)); From 8aa0d9e2cc04ca2730156a1ca903ad94e328c3a4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 7 Jan 2016 07:46:20 -0500 Subject: [PATCH 51/86] typo spotted --- doc/fixes36.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index b2c3197ca..a56b969b1 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -107,7 +107,7 @@ 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 for confirmation with "Is this ok?" before starting play -tty: responding with or duing role, race, &c selection +tty: responding with or during role, race, &c selection behaved same as to quit; now it will pick [random] instead unix/X11: in top level Makefile, some commented out definitions of VARDATND misspelled pilemark.xbm (as pilemark.xpm) From 0f5809c9248dce94fb598effaa48c2825245595a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 7 Jan 2016 22:38:33 +0200 Subject: [PATCH 52/86] Add some new database entries --- dat/data.base | 35 ++++++++++++++++++++++++++++++++--- doc/fixes36.1 | 2 ++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/dat/data.base b/dat/data.base index 960932c18..ed7674819 100644 --- a/dat/data.base +++ b/dat/data.base @@ -890,6 +890,12 @@ tiamat extremely vain. citrine* A pale yellow variety of crystalline quartz resembling topaz. +cleaver + Hither came Conan, the Cimmerian, black-haired, sullen-eyed, + sword in hand, a thief, a reaver, a slayer, with gigantic + melancholies and gigantic mirth, to tread the jeweled + thrones of the Earth under his sandalled feet. + [ The Phoenix on the Sword, by Robert E. Howard ] ~elven cloak ~oilskin cloak *cloak* @@ -1645,9 +1651,16 @@ fire trap _anywhere_?' [ The Last Hero, by Terry Pratchett ] f* brand - One of a pair of legendary swords that possess the powers - of elemental flame and ice, and will grant these to whoever - is fortunate enough to wield them. + Some say the world will end in fire, + Some say in ice. + From what I’ve tasted of desire + I hold with those who favor fire. + But if it had to perish twice, + I think I know enough of hate + To say that for destruction ice + Is also great + And would suffice. + [ Fire and Ice, by Robert Frost ] flesh golem With an anxiety that almost amounted to agony, I collected the instruments of life around me, that I might infuse a spark @@ -3920,6 +3933,17 @@ user Might just kill you. [ It's a Jungle Out There, by Randy Newman ] # [ theme song from "Monk" ] +polymorph trap + One morning, as Gregor Samsa was waking up from anxious dreams, + he discovered that in bed he had been changed into a monstrous + verminous bug. He lay on his armour-hard back and saw, as he + lifted his head up a little, his brown, arched abdomen divided + up into rigid bow-like sections. From this height the blanket, + just about ready to slide off completely, could hardly stay in + place. His numerous legs, pitifully thin in comparison to the + rest of his circumference, flickered helplessly before his eyes. + [ The Metamorphosis, by Franz Kafka, + translated by Ian Johnston ] pony Hey! now! Come hoy now! Whither do you wander? Up, down, near or far, here, there or yonder? @@ -4853,6 +4877,11 @@ straw golem figure was raised above the stalks of corn by means of the pole stuck up its back. [ The Wonderful Wizard of Oz, by L. Frank Baum ] +sunsword + What you seek is a blade of light, + a weapon for vengeance. + [ Expedition to Castle Ravenloft, + by Bruce Cordell and James Wyatt ] susano*o The Shinto chthonic and weather god and brother of the sun goddess Amaterasu, he was born from the nose of the diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a56b969b1..7e29a0101 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -144,6 +144,8 @@ wizard mode #wizintrinsic command additional tribute passages for The Colour of Magic, The Light Fantastic, Equal Rites, Snuff, and Raising Steam compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use +database entries for Cleaver, Sunsword, Frost and Fire brands, and + polymorph trap Platform- and/or Interface-Specific New Features From f16e9a88903c76d731030f93703b0dc2802468f6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 8 Jan 2016 07:55:56 +0200 Subject: [PATCH 53/86] Use plain ASCII for the database --- dat/data.base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dat/data.base b/dat/data.base index ed7674819..50152f2c1 100644 --- a/dat/data.base +++ b/dat/data.base @@ -1653,7 +1653,7 @@ fire trap f* brand Some say the world will end in fire, Some say in ice. - From what I’ve tasted of desire + From what I've tasted of desire I hold with those who favor fire. But if it had to perish twice, I think I know enough of hate From db234f743d99a770443174f2f7e74074305b9327 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 8 Jan 2016 00:38:34 -0800 Subject: [PATCH 54/86] integrate 'msgtype' option and Norep() Allow 'msgtype=show' for messages that nethack uses Norep() for. I don't know whether anyone will ever want to do that, but if felt strange to have two different message suppression mechanisms that were completely disconnected from each other. For a user with no msgtype filter, there'll be no difference in behavior. --- include/extern.h | 2 +- src/options.c | 5 +++-- src/pline.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/extern.h b/include/extern.h index 3e58ee565..70ce04b31 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1662,7 +1662,7 @@ E boolean FDECL(add_menu_coloring, (char *)); E boolean FDECL(get_menu_coloring, (char *, int *, int *)); E void NDECL(free_menu_coloring); E boolean FDECL(msgtype_parse_add, (char *)); -E int FDECL(msgtype_type, (const char *)); +E int FDECL(msgtype_type, (const char *, BOOLEAN_P)); E void NDECL(msgtype_free); /* ### pager.c ### */ diff --git a/src/options.c b/src/options.c index 11a26c074..f706d2c0a 100644 --- a/src/options.c +++ b/src/options.c @@ -1455,8 +1455,9 @@ int idx; /* 0 .. */ } int -msgtype_type(msg) +msgtype_type(msg, norepeat) const char *msg; +boolean norepeat; /* called from Norep(via pline) */ { struct plinemsg_type *tmp = plinemsg_types; @@ -1465,7 +1466,7 @@ const char *msg; return tmp->msgtype; tmp = tmp->next; } - return MSGTYP_NORMAL; + return norepeat ? MSGTYP_NOREP : MSGTYP_NORMAL; } int diff --git a/src/pline.c b/src/pline.c index ce4b60702..4ada9bff7 100644 --- a/src/pline.c +++ b/src/pline.c @@ -83,22 +83,22 @@ VA_DECL(const char *, line) iflags.last_msg = PLNMSG_UNKNOWN; return; } -#ifndef MAC - if (no_repeat && !strcmp(line, toplines)) + + msgtyp = msgtype_type(line, no_repeat); + if (msgtyp == MSGTYP_NOSHOW + || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg))) return; -#endif /* MAC */ if (vision_full_recalc) vision_recalc(0); if (u.ux) flush_screen(1); /* %% */ - msgtyp = msgtype_type(line); - if (msgtyp == MSGTYP_NOSHOW) return; - if (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg)) return; + putstr(WIN_MESSAGE, 0, line); /* this gets cleared after every pline message */ iflags.last_msg = PLNMSG_UNKNOWN; - strncpy(prevmsg, line, BUFSZ); - if (msgtyp == MSGTYP_STOP) display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */ + strncpy(prevmsg, line, BUFSZ), prevmsg[BUFSZ - 1] = '\0'; + if (msgtyp == MSGTYP_STOP) + display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */ #if !(defined(USE_STDARG) || defined(USE_VARARGS)) /* provide closing brace for the nested block From befc6a65b50068b46e44f2f1139d71d8e7c81d67 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 8 Jan 2016 22:17:37 +0200 Subject: [PATCH 55/86] TTY: Add menu_overlay option This was a request from a blind player. It's hard to find the left edge of the menu when it's drawn on the map, so clear the screen and align menus to the left edge of the screen when this option is turned off. Originally this was called the window edge patch. --- dat/opthelp | 1 + doc/Guidebook.mn | 4 ++++ doc/Guidebook.tex | 4 ++++ doc/fixes36.1 | 1 + include/flag.h | 1 + src/options.c | 5 +++++ win/tty/wintty.c | 8 +++++--- 7 files changed, 21 insertions(+), 3 deletions(-) diff --git a/dat/opthelp b/dat/opthelp index c378e618c..60531aae5 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -22,6 +22,7 @@ implicit_uncursed omit "uncursed" from inventory, if possible [TRUE] legacy print introductory message [TRUE] lit_corridor show a dark corridor as lit if in sight [FALSE] lootabc use a/b/c rather than o/i/b when looting [FALSE] +menu_overlay overlay menus on the screen and align to right [TRUE] mail enable the mail daemon [TRUE] null allow nulls to be sent to your terminal [TRUE] try turning this option off (forcing NetHack to use its own diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 2efd8bbf2..aa06e40c4 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -2218,6 +2218,10 @@ Default '>'. .lp menu_objsyms Show object symbols in menu headings in menus where the object symbols act as menu accelerators (default off). +.lp menu_overlay +Do not clear the screen before drawing menus, and align +menus to the right edge of the screen. Only for the tty port. +(default on) .lp menu_previous_page Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index cbb63f7a0..849476ef2 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2664,6 +2664,10 @@ Default `\verb+>+'. \item[\ib{menu\verb+_+objsyms}] Show object symbols in menu headings in menus where the object symbols act as menu accelerators (default off). +\item[\ib{menu\verb+_+overlay}] +Do not clear the screen before drawing menus, and align +menus to the right edge of the screen. Only for the tty port. +(default on) \item[\ib{menu\verb+_+previous\verb+_+page}] Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 7e29a0101..a58c4c95e 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -150,6 +150,7 @@ database entries for Cleaver, Sunsword, Frost and Fire brands, and Platform- and/or Interface-Specific New Features ------------------------------------------------ +tty: menu_overlay -option to clear screen and align menus to left NetHack Community Patches (or Variation) Included diff --git a/include/flag.h b/include/flag.h index bd6d2b2fc..a55591a13 100644 --- a/include/flag.h +++ b/include/flag.h @@ -199,6 +199,7 @@ struct instance_flags { boolean mention_walls; /* give feedback when bumping walls */ boolean menu_tab_sep; /* Use tabs to separate option menu fields */ boolean menu_head_objsym; /* Show obj symbol in menu headings */ + boolean menu_overlay; /* Draw menus over the map */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix * on some non-move commands */ boolean renameallowed; /* can change hero name during role selection */ diff --git a/src/options.c b/src/options.c index f706d2c0a..0e5332038 100644 --- a/src/options.c +++ b/src/options.c @@ -149,6 +149,11 @@ static struct Bool_Opt { /* for menu debugging only*/ { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_WIZGAME }, { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME }, +#ifdef TTY_GRAPHICS + { "menu_overlay", &iflags.menu_overlay, TRUE, SET_IN_GAME }, +#else + { "menu_overlay", (boolean *) 0, FALSE, SET_IN_FILE }, +#endif { "mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME }, /*WC*/ #ifdef NEWS { "news", &iflags.news, TRUE, DISP_IN_GAME }, diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 58dee65a3..0690f8e24 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2108,13 +2108,15 @@ boolean blocking; /* with ttys, all windows are blocking */ if (ttyDisplay->toplin == 1) tty_display_nhwindow(WIN_MESSAGE, TRUE); #ifdef H2344_BROKEN - if (cw->maxrow >= (int) ttyDisplay->rows) + if (cw->maxrow >= (int) ttyDisplay->rows + || !iflags.menu_overlay) #else - if (cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows) + if (cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows + || !iflags.menu_overlay) #endif { cw->offx = 0; - if (cw->offy) { + if (cw->offy || iflags.menu_overlay) { tty_curs(window, 1, 0); cl_eos(); } else From a2a1027be17b9af94899f4be58da3f31a15e4d12 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 02:19:29 +0200 Subject: [PATCH 56/86] Fix bz62: Pets walk into poison clouds Makes monsters who would be damaged by the poison cloud not walk into it --- doc/fixes36.1 | 1 + src/mon.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a58c4c95e..936bce369 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -99,6 +99,7 @@ fix weight of containers in special levels make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea +make monsters and pets avoid poison gas clouds if it would damage them Platform- and/or Interface-Specific Fixes diff --git a/src/mon.c b/src/mon.c index 08333c250..5978f1c20 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1172,6 +1172,9 @@ long flag; boolean wantpool, poolok, lavaok, nodiag; boolean rockok = FALSE, treeok = FALSE, thrudoor; int maxx, maxy; + boolean poisongas_ok, in_poisongas; + NhRegion *gas_reg; + int gas_glyph = cmap_to_glyph(S_poisoncloud); x = mon->mx; y = mon->my; @@ -1183,6 +1186,11 @@ long flag; || (is_swimmer(mdat) && !wantpool)); lavaok = (is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat)); thrudoor = ((flag & (ALLOW_WALL | BUSTDOOR)) != 0L); + poisongas_ok = ((nonliving(mdat) || is_vampshifter(mon) + || breathless(mdat)) || resists_poison(mon)); + in_poisongas = ((gas_reg = visible_region_at(x,y)) != 0 + && gas_reg->glyph == gas_glyph); + if (flag & ALLOW_DIG) { struct obj *mw_tmp; @@ -1231,6 +1239,11 @@ nexttry: /* eels prefer the water, but if there is no water nearby, || ((levl[nx][ny].doormask & D_LOCKED) && !(flag & UNLOCKDOOR))) && !thrudoor) continue; + /* avoid poison gas? */ + if (!poisongas_ok && !in_poisongas + && (gas_reg = visible_region_at(nx,ny)) != 0 + && gas_reg->glyph == gas_glyph) + continue; /* first diagonal checks (tight squeezes handled below) */ if (nx != x && ny != y && (nodiag From ff4a59ef23c7462b190fca1c1ff952edd65aa11e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 12:06:50 +0200 Subject: [PATCH 57/86] Fix bz258: Covetous monsters malfunction when there are no upstairs Make the monsters pick downstairs/ladders if the branch builds up (like Sokoban), otherwise try upstairs/ladders. --- src/wizard.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/wizard.c b/src/wizard.c index facacc799..830aa0a60 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -306,11 +306,49 @@ register struct monst *mtmp; return dstrat; } +void +choose_stairs(sx, sy) +xchar *sx; +xchar *sy; +{ + xchar x = 0, y = 0; + + if (builds_up(&u.uz)) { + if (xdnstair) { + x = xdnstair; + y = ydnstair; + } else if (xdnladder) { + x = xdnladder; + y = ydnladder; + } + } else { + if (xupstair) { + x = xupstair; + y = yupstair; + } else if (xupladder) { + x = xupladder; + y = yupladder; + } + } + + if (!x && sstairs.sx) { + x = sstairs.sx; + y = sstairs.sy; + } + + if (x && y) { + *sx = x; + *sy = y; + } + +} + int tactics(mtmp) register struct monst *mtmp; { unsigned long strat = strategy(mtmp); + xchar sx, sy; mtmp->mstrategy = (mtmp->mstrategy & (STRAT_WAITMASK | STRAT_APPEARMSG)) | strat; @@ -318,15 +356,14 @@ register struct monst *mtmp; switch (strat) { case STRAT_HEAL: /* hide and recover */ /* if wounded, hole up on or near the stairs (to block them) */ - /* unless, of course, there are no stairs (e.g. endlevel) */ + choose_stairs(&sx, &sy); mtmp->mavenge = 1; /* covetous monsters attack while fleeing */ if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) - || (mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) { + || (mtmp->iswiz && !sx && !mon_has_amulet(mtmp))) { if (!rn2(3 + mtmp->mhp / 10)) (void) rloc(mtmp, TRUE); - } else if (xupstair - && (mtmp->mx != xupstair || mtmp->my != yupstair)) { - (void) mnearto(mtmp, xupstair, yupstair, TRUE); + } else if (sx && (mtmp->mx != sx || mtmp->my != sy)) { + (void) mnearto(mtmp, sx, sy, TRUE); } /* if you're not around, cast healing spells */ if (distu(mtmp->mx, mtmp->my) > (BOLT_LIM * BOLT_LIM)) From 7e4e9f263a4e5d182553ee96668311b391fdeb8d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 13:16:43 +0200 Subject: [PATCH 58/86] Update fixes --- doc/fixes36.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 936bce369..9149325ef 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -100,6 +100,7 @@ make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea make monsters and pets avoid poison gas clouds if it would damage them +covetous monsters may choose to teleport to downstairs or ladders Platform- and/or Interface-Specific Fixes From 1e1557ed46466bbcad5f1b1e1dde48f4c5be9fcd Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 13:39:45 +0200 Subject: [PATCH 59/86] Add extended command #kick I've seen some complaints about not being able to kick with ^d so add kick as an extended command. Also add the missing #exploremode command to the Guidebook. --- doc/Guidebook.mn | 4 ++++ doc/Guidebook.tex | 6 ++++++ src/cmd.c | 1 + 3 files changed, 11 insertions(+) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index aa06e40c4..2d73781f5 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -860,12 +860,16 @@ See the section below entitled ``Conduct'' for details. Dip an object into something. .lp #enhance Advance or check weapon and spell skills. +.lp #exploremode +Enter the explore mode. .lp #force Force a lock. .lp #invoke Invoke an object's special powers. .lp #jump Jump to another location. +.lp #kick +Kick something. .lp #loot Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 849476ef2..53716a2a9 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1042,6 +1042,9 @@ Dip an object into something. \item[\tb{\#enhance}] Advance or check weapon and spell skills. %.lp +\item[\tb{\#exploremode}] +Enter the explore mode. +%.lp \item[\tb{\#force}] Force a lock. %.lp @@ -1051,6 +1054,9 @@ Invoke an object's special powers. \item[\tb{\#jump}] Jump to another location. %.lp +\item[\tb{\#kick}] +Kick something. +%.lp \item[\tb{\#loot}] Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. diff --git a/src/cmd.c b/src/cmd.c index 162234a76..1b389f722 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2777,6 +2777,7 @@ struct ext_func_tab extcmdlist[] = { { "force", "force a lock", doforce, FALSE }, { "invoke", "invoke an object's powers", doinvoke, TRUE }, { "jump", "jump to a location", dojump, FALSE }, + { "kick", "kick something", dokick, FALSE }, { "loot", "loot a box on the floor", doloot, FALSE }, { "monster", "use a monster's special ability", domonability, TRUE }, { "name", "name a monster or an object", docallcmd, TRUE }, From 7e3f82ed3ca07ec8a2d56068eb01b330ca9b857f Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 9 Jan 2016 13:57:15 -0800 Subject: [PATCH 60/86] fix #H4187 - doppelgangers posing as Riders... ... never transform and can leave Rider corpses Riders can't be polymorphed, and the code to prevent that was also preventing doppelgangers in Rider form from changing shape. Using ring of protection from shape changers effectively turned such doppelgangers into actual Riders which would leave self-reviving corpses. That didn't prevent Riders from appearing on the Astral Plane though. --- doc/fixes36.1 | 3 +++ src/mon.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 9149325ef..49dc28c48 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -101,6 +101,9 @@ fix possible segfault in lev_comp when map was too tall fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea make monsters and pets avoid poison gas clouds if it would damage them covetous monsters may choose to teleport to downstairs or ladders +doppelganger posing as Rider would never change shape +since doppelganger posing as Rider could never revert to innate form, + protection from shape changers turned it into genuine Rider Platform- and/or Interface-Specific Fixes diff --git a/src/mon.c b/src/mon.c index 5978f1c20..802d20bff 100644 --- a/src/mon.c +++ b/src/mon.c @@ -3157,8 +3157,9 @@ boolean msg; /* "The oldmon turns into a newmon!" */ struct permonst *olddata = mtmp->data; char oldname[BUFSZ], l_oldname[BUFSZ], newname[BUFSZ]; - /* Riders are immune to polymorph and green slime */ - if (is_rider(mtmp->data)) + /* Riders are immune to polymorph and green slime + (but apparent Rider might actually be a doppelganger) */ + if (is_rider(mtmp->data) && mtmp->cham == NON_PM) return 0; if (msg) { From 3a8ce3ff981bca3e60135c0fe94e33b9175dda3c Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 9 Jan 2016 15:28:25 -0800 Subject: [PATCH 61/86] fix #H4083 - globs preID'd as "uncursed" I think there was also a report about this during beta testing. Killing an ooze, slime, or pudding left a glob of same which had its bknown flag pre-set so was immediately shown as "uncursed" even to non-priests. Use another way to maximize glob mergability: allow globs to merge even when one has bknown set and the other doesn't. --- doc/fixes36.1 | 4 ++++ src/invent.c | 35 +++++++++++++++++++++++++++-------- src/mkobj.c | 8 +++----- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 49dc28c48..174c21b95 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -104,6 +104,10 @@ covetous monsters may choose to teleport to downstairs or ladders doppelganger posing as Rider would never change shape since doppelganger posing as Rider could never revert to innate form, protection from shape changers turned it into genuine Rider +don't create globs of ooze/slime/pudding with bknown flag set so pre-known to + be "uncursed" +do allow globs with same curse/bless state to merge even when that state is + known for one and unknown for the other; result will have bknown clear Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index a79c7d46b..94ae77d7c 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2880,24 +2880,46 @@ mergable(otmp, obj) register struct obj *otmp, *obj; { int objnamelth = 0, otmpnamelth = 0; + if (obj == otmp) return FALSE; /* already the same object */ if (obj->otyp != otmp->otyp) + return FALSE; /* different types */ + if (obj->nomerge) /* explicitly marked to prevent merge */ return FALSE; + /* coins of the same kind will always merge */ if (obj->oclass == COIN_CLASS) return TRUE; + if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe || obj->dknown != otmp->dknown - || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit - || obj->greased != otmp->greased || obj->oeroded != otmp->oeroded - || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass) + || obj->bypass != otmp->bypass) return FALSE; - if (obj->nomerge) /* explicitly marked to prevent merge */ + if (obj->oclass == FOOD_CLASS + && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) + return FALSE; + + if (obj->globby) { + /* globs won't merge if they have different bless/curse + state, but will merge non-bknown with bknown */ + if (obj->bknown != otmp->bknown) + obj->bknown = otmp->bknown = 0; + if (obj->rknown != otmp->rknown) + obj->rknown = otmp->rknown = 0; + if (obj->greased != otmp->greased) + obj->greased = otmp->greased = 0; + /* checks beyond this point aren't applicable to globs */ + return TRUE; + } + + if ((obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) + || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2 + || obj->greased != otmp->greased) return FALSE; if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS) @@ -2905,10 +2927,6 @@ register struct obj *otmp, *obj; || obj->rknown != otmp->rknown)) return FALSE; - if (obj->oclass == FOOD_CLASS - && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) - return FALSE; - if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) { if (obj->corpsenm != otmp->corpsenm) return FALSE; @@ -3413,6 +3431,7 @@ doorganize() /* inventory organizer by Del Lamb */ names, strip off the name of the one being moved */ if (olth && !obj->oartifact && !mergable(otmp, obj)) { char *holdname = ONAME(obj); + ONAME(obj) = (char *) 0; /* restore name iff merging is still not possible */ if (!mergable(otmp, obj)) { diff --git a/src/mkobj.c b/src/mkobj.c index 9a1023117..a6f8bfd29 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -819,11 +819,9 @@ boolean artif; } if (Is_pudding(otmp)) { otmp->globby = 1; - otmp->known = otmp->bknown = otmp->rknown = otmp->dknown = 1; - otmp->corpsenm = - PM_GRAY_OOZE + (otmp->otyp - GLOB_OF_GRAY_OOZE); - /* this ensures that they don't fail merging because of - * BUC status or other irrelevancies */ + otmp->known = otmp->dknown = 1; + otmp->corpsenm = PM_GRAY_OOZE + + (otmp->otyp - GLOB_OF_GRAY_OOZE); } else { if (otmp->otyp != CORPSE && otmp->otyp != MEAT_RING && otmp->otyp != KELP_FROND && !rn2(6)) { From e1f8deb63fe93adad16df8e04dac6acd64899b27 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 9 Jan 2016 18:17:15 -0800 Subject: [PATCH 62/86] tribute: Mort --- dat/tribute | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 262 insertions(+), 6 deletions(-) diff --git a/dat/tribute b/dat/tribute index 53cfbd985..462e4743e 100644 --- a/dat/tribute +++ b/dat/tribute @@ -800,11 +800,260 @@ shelves, but not to prevent them being stolen.... # # # -%title Mort (1) +%title Mort (11) +# p. 136 (Signet edition; passage is a footnote; +# Vetinari doesn't show up as recurring Patrician until /Sourcery/) %passage 1 -Ankh-Morpork had dallied with many forms of government and hand ended up - with that form of democracy known as One Man, One Vote. The Patrician was -the Man; he had the Vote. +Ankh-Morpork had dallied with many forms of government and had ended up +with that form of democracy known as One Man, One Vote. The Patrician was +the Man; he had the Vote. + + [Mort, by Terry Pratchett] +%e passage +# p. 11 +%passage 2 +Mort was getting interested in the rock. It had curly shells in it, relics +of the early days of the world when the Creator had made creatures out of +stone, no-one knew why. + +Mort was interested in lots of things. Why people's teeth fitted together +so neatly, for example. He'd given that one a lot of thought. Then there +was the puzzle of why the sun came out during the day, instead of at night +when the light would come in useful. He knew the standard explanation, +which somehow didn't seem satisfying. + +In short, Mort is one of those people who are more dangerous than a bag +full of rattlesnakes. He was determined to discover the underlying logic +behind the universe. + +Which was going to be hard, because there wasn't one. The Creator had a +lot of remarkably good ideas when he put the world together, but making it +understandable hadn't been one of them. + + [Mort, by Terry Pratchett] +%e passage +# p. 18 +%passage 3 +"But you're Death," said Mort. "You go around killing people!" + +I? KILL? said Death, obviously offended. CERTAINLY NOT. PEOPLE /GET/ +KILLED, BUT THAT'S THEIR BUSINESS. I JUST TAKE OVER FROM THEN ON. AFTER +ALL, IT'D BE A BLOODY STUPID WORLD IF PEOPLE GOT KILLED WITHOUT DYING, +WOULDN'T IT? + + [Mort, by Terry Pratchett] +%e passage +# p. 25 +%passage 4 +"Is it magic?" said Mort. + +WHAT DO YOU THINK? said Death. AM I REALLY HERE, BOY? + +"Yes," said Mort slowly. "I... I've watched people. They look at you but +the don't see you, I think. You do something to their minds." + +Death shook his head. + +THEY DO IT ALL THEMSELVES, he said. THERE'S NO MAGIC. PEOPLE CAN'T SEE ME, +THEY SIMPLY WON'T ALLOW THEMSELVES TO DO IT. UNTIL IT'S TIME, OF COURSE. +WIZARDS CAN SEE ME, AND CATS. BUT YOUR AVERAGE HUMAN... NO, NEVER. He blew +a smoke ring at the sky, and added, STRANGE BUT TRUE. + + [Mort, by Terry Pratchett] +%e passage +# pp. 48-49 (Binky is Death's white horse, who was left 'parked' on a +# castle's roof; Mort is Death's novice apprentice) +%passage 5 +They were on the roof before he spoke again. + +YOU TRIED TO WARN HIM, he said, removing Binky's nosebag. + +"Yes, sir. Sorry." + +YOU CANNOT INTERFERE WITH FATE. WHO ARE YOU TO JUDGE WHO SHOULD LIVE AND +WHO SHOULD DIE? + +Death watched Mort's expression carefully. + +ONLY THE GODS ARE ALLOWED TO DO THAT, he added. TO TINKER WITH THE FATE OF +EVEN ONE INDIVIDUAL COULD DESTROY THE WHOLE WORLD. DO YOU UNDERSTAND? + +Mort nodded miserably. + +"Are you going to send me home?" he said. + +Death reached down and swung him up behind the saddle. + +BECAUSE YOU SHOWED COMPASSION? NO. I MIGHT HAVE DONE IF YOU HAD SHOWN +PLEASURE. BUT YOU MUST LEARN THE COMPASSION PROPER TO YOUR TRADE. + +"What's that?" + +A /SHARP/ EDGE. + + [Mort, by Terry Pratchett] +%e passage +# pp. 59-61 (in Ankh-Morpork, Mort has accidentally walked through a wall +# into an immigrant Klatchian family's dining room; 'the creature +# who was not there' refers to Death during an earlier event) +%passage 6 +"I'm no demon! I'm a human!" he said, and stopped in shock as his words +emerged in perfect Klatch. + +"You're a thief?" said the father. "A murderer? To creep in thus, are you +a /tax-gatherer/?" His hand slipped under the table and came up holding a +meat cleaver honed to paper thinness. His wife screamed and dropped the +plate and clutched the youngest children to her. + +Mort watched the blade weave through the air, and gave in. + +"I bring you greetings from the uttermost circles of hell," he hazarded. + +The change was remarkable. The cleaver was lowered and the family broke +into broad smiles. + +"There is much luck to us if a demon visits," beamed the father. "What is +your wish, O foul spawn of Offler's loins?" + +"Sorry?" said Mort. + +"A demon brings blessing and good fortune on the man that helps it," said +the man. "How may we be of assistance, O evil dogsbreath of the nether +pit?" + +"Well, I'm not very hungry," said Mort, "but if you know where I can get a +fast horse, I could be in Sto Lat before sunset." + +The man beamed and bowed. "I know the very place, noxious extrusion of the +bowels, if you would be so good as to follow me." + +Mort hurried out after him. The ancient ancestor watched them go with a +critical expression, its jowls rhymically chewing. + +"That was what they call a demon around here?" it said. "Offler rot this +country of dampness, even their demons are third-rate, not a patch on the +demons we had in the Old Country." + +The wife placed a small bowl of rice in the folded middle pair of hands of +the Offler statue (it would be gone in the morning) and stood back. + +"Husband did say that last month at the /Curry Gardens/ he served a creature +who was not there," she said. "He was impressed." + +Ten minutes later the man returned and, in solemn silence, placed a small +heap of gold coins on the table. They represented enough wealth to +purchase quite a large part of the city. + +"He had a bag of them," he said. + +The family stared at the money for some time. The wife sighed. + +"Riches bring many problems," she said. "What are we to do?" + +"We return to Klatch," said the husband firmly, "where our children can grow +up in a proper country, true to the glorious traditions of our ancient race +and men do not need to work as waiters for wicked masters but can stand tall +and proud. And we must leave right now, fragrant blossom of the date palm." + +"Why so soon, O hard-working son of the desert?" + +"Because," said the man, "I have just sold the Patrician's champion +racehorse." + + [Mort, by Terry Pratchett] +%e passage +# p. 139-140 (passage ends mid-sentence) +%passage 7 +"You don't know much about monarchy, do you?" said Keli. + +"Um, no?" + +"She means better to be a dead queen in your own castle than a live +commoner somewhere else," said Cutwell, [...] + + [Mort, by Terry Pratchett] +%e passage +# p. 158 +%passage 8 +"You mean you won't help?" said Mort. "Not even if you can?" + +"Give the boy a prize," growled Albert. "And it's no good thinking you can +appeal to my better nature under this here crusty exterior," he added, +"'cos my interior's pretty damn crusty too." + + [Mort, by Terry Pratchett] +%e passage +# p. 159-160 (Death has come to an employment agency--a new concept in +# Ankh-Morpork--looking for a job) +%passage 9 +"And what was your previous position?" + +I BEG YOUR PARDON? + +"What did you do for a living?" said the thin young man behind the desk. + +I USHERED SOULS INTO THE NEXT WORLD. I WAS THE GRAVE OF ALL HOPE. I WAS +THE ULTIMATE REALITY. I WAS THE ASSASSIN AGAINST WHOM NO LOCK WOULD HOLD. + +"Yes, point taken, but do you have any particular skills?" + +I SUPPOSE A CERTAIN AMOUNT OF EXPERTISE WITH AGRICULTURAL IMPLEMENTS? he +ventured after a while. + +The young man shook his head firmly. + +NO? + + [Mort, by Terry Pratchett] +%e passage +# p. 205 +%passage 10 +Death raised his skull and sniffed the air. + +The sound cut through all the other noises in the hall and forced them +into silence. + +It is the kind of noise that is heard on the twilight edges of dreams, +the sort that you wake from in the cold sweat of mortal horror. It was +the snuffling under the door of dread. It was like the snuffling of a +hedgehog, but if so then it was the kind of hedgehog that crashes out of +the verges and flattens lorries. It was the kind of noise you wouldn't +want to hear twice; you wouldn't want to hear it /once/. + + [Mort, by Terry Pratchett] +%e passage +# p. 207 +%passage 11 +"Well, that was a lesson to all of us," the bursar continued, brushing dust +and candle wax off his robe. He looked up, expecting to see the statue of +Alberto Malich back on its pedestal. + +"Clearly even statues have feelings," he said. "I myself recall, when I +was but a first-year student, writing my name on his... well, never mind. +The point is, I propose here and now we replace the statue." + +Dead silence greeted this suggestion. + +"With, say, an exact likeness cast in gold. Suitably embellished with +jewels, as befits our great founder," he went on brightly. + +"And to make sure no students deface it in any way I suggest we then erect +it in the deepest cellar," he continued. + +"And then lock the door," he added. Several wizards began to cheer up. + +"And throw away the key?" said Rincewind. + +"And /weld/ the door," the bursar said. He had just remembered about The +Mended Drum. He thought for a while and remembered about the physical +fitness regime as well. + +"And then brick up the doorway," he said. There was a round of applause. + +"And throw away the brick layer!" chortled Rincewind, who felt he was +getting the hang of this. + +The bursar scowled at him. "No need to get carried away," he said. [Mort, by Terry Pratchett] %e passage @@ -6390,7 +6639,7 @@ IF YOU ASK ME, said Death, NOBODY COULD DO ANY BETTER THAN THAT... # Used for interaction with Death. # %section Death -%title Death Quotes (17) +%title Death Quotes (19) %passage 1 WHERE THE FIRST PRIMAL CELL WAS, THERE WAS I ALSO. WHERE MAN IS, THERE AM I. WHEN THE LAST LIFE CRAWLS UNDER FREEZING STARS, THERE WILL I BE. %e passage @@ -6443,7 +6692,8 @@ I HAVE COME FOR THEE. # including them here wouldn't fit with the rest) %passage 14 DARK IN HERE, ISN'T IT? -# p. 14 (Equal Rites; 2nd sentence continues 'said the deep, heavy voice...') +# Equal Rites, p. 14 (Signet edition; second sentence continues +# 'said the deep, heavy voice...') %passage 15 THERE IS NO GOING BACK. THERE IS NO GOING BACK. # p. 15 (contradicts later descriptions of Death as existing outside of time; @@ -6453,6 +6703,12 @@ I HAVEN'T GOT ALL DAY, YOU KNOW. # p. 15 (same page) %passage 17 LIFE IS FOR THE LIVING. +# Mort, p. 148 (Signet edition) +%passage 18 +NO-ONE EVER WANTED TO TALK TO ME BEFORE. +# p. 149 +%passage 19 +I HAVEN'T GOT A SINGLE FRIEND. EVEN CATS FIND ME AMUSING. %e title %e section # From 653f75edc1ee8a6cafd43f7f0a4c131d24bc54c7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 10:09:56 +0200 Subject: [PATCH 63/86] Add missing variable init --- src/wizard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wizard.c b/src/wizard.c index 830aa0a60..57d4d6cbe 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -348,7 +348,7 @@ tactics(mtmp) register struct monst *mtmp; { unsigned long strat = strategy(mtmp); - xchar sx, sy; + xchar sx = 0, sy = 0; mtmp->mstrategy = (mtmp->mstrategy & (STRAT_WAITMASK | STRAT_APPEARMSG)) | strat; From e7d65a44cd93384bb526e2c3f448407ba62fd8de Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 10:35:27 +0200 Subject: [PATCH 64/86] TTY: Add compile-time option for tile data hinting Several people have asked if 3.6.0 supports playing with tiles on a public server. Because there's no way for the user's end to know what that white @ is, this adds special console escape codes for tile hinting. The idea was originally a patch called TelnetTiles by Justin Hiltscher, but this expanded version comes via NAO, where it's been in use for years. This is basically an interim hack, which should go away when/if we support actual client-server model. --- doc/fixes36.1 | 1 + include/config.h | 33 +++++++++++++++++++++++ include/flag.h | 3 +++ src/options.c | 5 ++++ util/makedefs.c | 3 +++ win/tty/wintty.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 174c21b95..a14453683 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -160,6 +160,7 @@ database entries for Cleaver, Sunsword, Frost and Fire brands, and Platform- and/or Interface-Specific New Features ------------------------------------------------ tty: menu_overlay -option to clear screen and align menus to left +tty: compile-time option to output escape codes for tile data hints NetHack Community Patches (or Variation) Included diff --git a/include/config.h b/include/config.h index 3392e6407..72f87fb11 100644 --- a/include/config.h +++ b/include/config.h @@ -439,6 +439,33 @@ typedef unsigned char uchar; * bugs left here. */ +/* TTY_TILES_ESCCODES: Enable output of special console escape codes + * which act as hints for external programs such as EbonHack. + * + * Only for TTY_GRAPHICS. + * + * All of the escape codes are in the format ESC [ N z, where N can be + * one or more positive integer values, separated by semicolons. + * For example ESC [ 1 ; 0 ; 120 z + * + * Possible codes are: + * ESC [ 1 ; 0 ; n ; m z Start a glyph (aka a tile) number n, with flags m + * ESC [ 1 ; 1 z End a glyph. + * ESC [ 1 ; 2 ; n z Select a window n to output to. + * ESC [ 1 ; 3 z End of data. NetHack has finished sending data, + * and is waiting for input. + * + * Whenever NetHack outputs anything, it will first output the "select window" + * code. Whenever NetHack outputs a tile, it will first output the "start + * glyph" code, then the escape codes for color and the glyph character + * itself, and then the "end glyph" code. + * + * To compile NetHack with this, add tile.c to WINSRC and tile.o to WINOBJ + * in the hints file or Makefile. + * Set boolean option vt_tiledata in your config file to turn this on. + * Note that gnome-terminal at least doesn't work with this. */ +/* #define TTY_TILES_ESCCODES */ + /* #define STATUS_VIA_WINDOWPORT */ /* re-work of the status line updating process */ /* #define STATUS_HILITES */ /* support hilites of status fields */ @@ -459,6 +486,12 @@ typedef unsigned char uchar; /* End of Section 4 */ +#ifdef TTY_TILES_ESCCODES +# ifndef USE_TILES +# define USE_TILES +# endif +#endif + #include "global.h" /* Define everything else according to choices above */ #endif /* CONFIG_H */ diff --git a/include/flag.h b/include/flag.h index a55591a13..79da89f92 100644 --- a/include/flag.h +++ b/include/flag.h @@ -259,6 +259,9 @@ struct instance_flags { #ifdef LAN_FEATURES boolean lan_mail; /* mail is initialized */ boolean lan_mail_fetched; /* mail is awaiting display */ +#endif +#ifdef TTY_TILES_ESCCODES + boolean vt_tiledata; /* output console codes for tile support in TTY */ #endif boolean wizweight; /* display weight of everything in wizard mode */ /* diff --git a/src/options.c b/src/options.c index 0e5332038..8c47c6ae4 100644 --- a/src/options.c +++ b/src/options.c @@ -225,6 +225,11 @@ static struct Bool_Opt { { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/ #endif { "verbose", &flags.verbose, TRUE, SET_IN_GAME }, +#ifdef TTY_TILES_ESCCODES + { "vt_tiledata", &iflags.vt_tiledata, FALSE, SET_IN_FILE }, +#else + { "vt_tiledata", (boolean *) 0, FALSE, SET_IN_FILE }, +#endif { "wizweight", &iflags.wizweight, FALSE, SET_IN_WIZGAME }, { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME }, #ifdef ZEROCOMP diff --git a/util/makedefs.c b/util/makedefs.c index 0e340b478..64f9b7fe5 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1323,6 +1323,9 @@ static const char *build_opts[] = { #ifdef TEXTCOLOR "color", #endif +#ifdef TTY_TILES_ESCCODES + "console escape codes for tile hinting", +#endif #ifdef COM_COMPL "command line completion", #endif diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 0690f8e24..27d53180a 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -37,6 +37,15 @@ extern void msmsg(const char *, ...); #endif #endif +#ifdef TTY_TILES_ESCCODES +extern short glyph2tile[]; +#define TILE_ANSI_COMMAND 'z' +#define AVTC_GLYPH_START 0 +#define AVTC_GLYPH_END 1 +#define AVTC_SELECT_WINDOW 2 +#define AVTC_INLINE_SYNC 3 +#endif + extern char mapped_menu_cmds[]; /* from options.c */ /* this is only needed until tty_status_* routines are written */ @@ -175,6 +184,36 @@ static const char default_menu_cmds[] = { MENU_INVERT_PAGE, MENU_SEARCH, 0 /* null terminator */ }; +#ifdef TTY_TILES_ESCCODES +static int vt_tile_current_window = -2; + +void +print_vt_code(i, c, d) +int i, c, d; +{ + if (iflags.vt_tiledata) { + if (c >= 0) { + if (i == AVTC_SELECT_WINDOW) { + if (c == vt_tile_current_window) return; + vt_tile_current_window = c; + } + if (d >= 0) + printf("\033[1;%d;%d;%d%c", i, c, d, TILE_ANSI_COMMAND); + else + printf("\033[1;%d;%d%c", i, c, TILE_ANSI_COMMAND); + } else { + printf("\033[1;%d%c", i, TILE_ANSI_COMMAND); + } + } +} +#else +# define print_vt_code(i, c, d) ; +#endif /* !TTY_TILES_ESCCODES */ +#define print_vt_code1(i) print_vt_code((i), -1, -1) +#define print_vt_code2(i,c) print_vt_code((i), (c), -1) +#define print_vt_code3(i,c,d) print_vt_code((i), (c), (d)) + + /* clean up and quit */ STATIC_OVL void bail(mesg) @@ -1427,6 +1466,8 @@ winid window; panic(winpanicstr, window); ttyDisplay->lastwin = window; + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin) { @@ -2060,6 +2101,8 @@ boolean blocking; /* with ttys, all windows are blocking */ ttyDisplay->lastwin = window; ttyDisplay->rawprint = 0; + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin == 1) { @@ -2145,6 +2188,8 @@ winid window; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin) @@ -2214,6 +2259,8 @@ register int x, y; /* not xchar: perhaps xchar is unsigned and panic(winpanicstr, window); ttyDisplay->lastwin = window; + print_vt_code2(AVTC_SELECT_WINDOW, window); + #if defined(USE_TILES) && defined(MSDOS) adjust_cursor_flags(cw); #endif @@ -2302,6 +2349,8 @@ char ch; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_STATUS: case NHW_MAP: @@ -2369,6 +2418,8 @@ const char *str; ttyDisplay->lastwin = window; + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: /* really do this later */ @@ -3065,9 +3116,13 @@ int bkglyph UNUSED; /* map glyph to character and color */ (void) mapglyph(glyph, &ch, &color, &special, x, y); + print_vt_code2(AVTC_SELECT_WINDOW, window); + /* Move the cursor. */ tty_curs(window, x, y); + print_vt_code3(AVTC_GLYPH_START, glyph2tile[glyph], special); + #ifndef NO_TERMS if (ul_hack && ch == '_') { /* non-destructive underscore */ (void) putchar((char) ' '); @@ -3111,6 +3166,8 @@ int bkglyph UNUSED; #endif } + print_vt_code1(AVTC_GLYPH_END); + wins[window]->curx++; /* one character over */ ttyDisplay->curx++; /* the real cursor moved too */ } @@ -3121,6 +3178,7 @@ const char *str; { if (ttyDisplay) ttyDisplay->rawprint++; + print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE); #if defined(MICRO) || defined(WIN32CON) msmsg("%s\n", str); #else @@ -3135,6 +3193,7 @@ const char *str; { if (ttyDisplay) ttyDisplay->rawprint++; + print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE); term_start_raw_bold(); #if defined(MICRO) || defined(WIN32CON) msmsg("%s", str); @@ -3153,7 +3212,7 @@ const char *str; int tty_nhgetch() { - int i; + int i, tmp; #ifdef UNIX /* kludge alert: Some Unix variants return funny values if getc() * is called, interrupted, and then called again. There @@ -3164,6 +3223,7 @@ tty_nhgetch() char nestbuf; #endif + print_vt_code1(AVTC_INLINE_SYNC); (void) fflush(stdout); /* Note: if raw_print() and wait_synch() get called to report terminal * initialization problems, then wins[] and ttyDisplay might not be @@ -3186,6 +3246,12 @@ tty_nhgetch() i = '\033'; /* same for EOF */ if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; +#ifdef TTY_TILES_ESCCODES + /* hack to force output of the window select code */ + tmp = vt_tile_current_window; + vt_tile_current_window++; + print_vt_code2(AVTC_SELECT_WINDOW, tmp); +#endif /* TTY_TILES_ESCCODES */ return i; } From 65d780dc3d1a176d834c0b0ced197d5eaaa21428 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 13:01:46 +0200 Subject: [PATCH 65/86] Add compile-time option MSGHANDLER This was a feature request from a blind player; he wanted to play a sound whenever a pline message was given. --- doc/fixes36.1 | 1 + include/config.h | 6 ++++++ src/pline.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ util/makedefs.c | 3 +++ 4 files changed, 56 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a14453683..c3b17ca0f 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -161,6 +161,7 @@ Platform- and/or Interface-Specific New Features ------------------------------------------------ tty: menu_overlay -option to clear screen and align menus to left tty: compile-time option to output escape codes for tile data hints +unix: compile-time option MSGHANDLER to pass messages to external program NetHack Community Patches (or Variation) Included diff --git a/include/config.h b/include/config.h index 72f87fb11..121ce5407 100644 --- a/include/config.h +++ b/include/config.h @@ -466,6 +466,12 @@ typedef unsigned char uchar; * Note that gnome-terminal at least doesn't work with this. */ /* #define TTY_TILES_ESCCODES */ +/* NetHack will execute an external program whenever a new message-window + * message is shown. The program to execute is given in environment variable + * NETHACK_MSGHANDLER. It will get the message as the only parameter. + * Only available with POSIX_TYPES or GNU C */ +/* #define MSGHANDLER */ + /* #define STATUS_VIA_WINDOWPORT */ /* re-work of the status line updating process */ /* #define STATUS_HILITES */ /* support hilites of status fields */ diff --git a/src/pline.c b/src/pline.c index 4ada9bff7..141532cad 100644 --- a/src/pline.c +++ b/src/pline.c @@ -10,6 +10,9 @@ static boolean no_repeat = FALSE; static char prevmsg[BUFSZ]; static char *FDECL(You_buf, (int)); +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) +static void FDECL(execplinehandler, (const char *)); +#endif /*VARARGS1*/ /* Note that these declarations rely on knowledge of the internals @@ -94,6 +97,11 @@ VA_DECL(const char *, line) flush_screen(1); /* %% */ putstr(WIN_MESSAGE, 0, line); + +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) + execplinehandler(line); +#endif + /* this gets cleared after every pline message */ iflags.last_msg = PLNMSG_UNKNOWN; strncpy(prevmsg, line, BUFSZ), prevmsg[BUFSZ - 1] = '\0'; @@ -585,4 +593,42 @@ struct obj *otmp2; } } +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) +static boolean use_pline_handler = TRUE; +static void +execplinehandler(line) +const char *line; +{ + int f; + const char *args[3]; + char *env; + + if (!use_pline_handler) + return; + + if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) { + use_pline_handler = FALSE; + return; + } + + f = fork(); + if (f == 0) { /* child */ + args[0] = env; + args[1] = line; + args[2] = NULL; + (void) setgid(getgid()); + (void) setuid(getuid()); + (void) execv(args[0], (char *const *) args); + perror((char *) 0); + (void) fprintf(stderr, "Exec to message handler %s failed.\n", + env); + terminate(EXIT_FAILURE); + } else if (f == -1) { + perror((char *) 0); + use_pline_handler = FALSE; + pline("Fork to message handler failed."); + } +} +#endif /* defined(POSIX_TYPES) || defined(__GNUC__) */ + /*pline.c*/ diff --git a/util/makedefs.c b/util/makedefs.c index 64f9b7fe5..a20660c7c 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1350,6 +1350,9 @@ static const char *build_opts[] = { #ifdef HOLD_LOCKFILE_OPEN "exclusive lock on level 0 file", #endif +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) + "external program as a message handler", +#endif #ifdef LOGFILE "log file", #endif From c6bf49f647b799a1099885a28bed46cec71d3e8e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 14:47:06 +0200 Subject: [PATCH 66/86] Small code cleanup --- src/do_name.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index da48c07dc..158189e39 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -103,6 +103,7 @@ int *cnt_p; boolean do_mons; { int x, y, pass, glyph, idx; + boolean wantedloc; *cnt_p = idx = 0; for (pass = 0; pass < 2; pass++) { @@ -118,31 +119,19 @@ boolean do_mons; for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { glyph = glyph_at(x, y); - if (do_mons) { - /* unlike '/M', this skips monsters revealed by - * warning glyphs and remembered invisible ones; - * TODO: skip worm tails - */ - if (glyph_is_monster(glyph)) { - if (!pass) { - ++*cnt_p; - } else { - (*arr_p)[idx].x = x; - (*arr_p)[idx].y = y; - ++idx; - } - } - } else { /* objects */ - /* TODO: skip boulders and rocks */ - if (glyph_is_object(glyph)) { - if (!pass) { - ++*cnt_p; - } else { - (*arr_p)[idx].x = x; - (*arr_p)[idx].y = y; - ++idx; - } - } + /* unlike '/M', this skips monsters revealed by + * warning glyphs and remembered invisible ones; + * TODO: skip worm tails, boulders and rocks + */ + wantedloc = (do_mons && glyph_is_monster(glyph) + || !do_mons && glyph_is_object(glyph)); + if (!wantedloc) continue; + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; } } } /* pass */ From fe01018d90602a2f82ef88f14edce41cc90d1216 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 15:03:23 +0200 Subject: [PATCH 67/86] Enable TIMED_DELAY for linux hints files runmode is completely useless in TTY without this --- sys/unix/hints/linux | 1 + sys/unix/hints/linux-chroot | 1 + 2 files changed, 2 insertions(+) diff --git a/sys/unix/hints/linux b/sys/unix/hints/linux index a9b612edb..888fd9050 100644 --- a/sys/unix/hints/linux +++ b/sys/unix/hints/linux @@ -23,6 +23,7 @@ POSTINSTALL=cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INS CFLAGS=-g -O -I../include -DNOTPARMDECL $(CFLAGS1) -DDLB CFLAGS1=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE +CFLAGS+=-DTIMED_DELAY CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" LINK=$(CC) diff --git a/sys/unix/hints/linux-chroot b/sys/unix/hints/linux-chroot index d8af97580..404f4db98 100644 --- a/sys/unix/hints/linux-chroot +++ b/sys/unix/hints/linux-chroot @@ -27,6 +27,7 @@ POSTINSTALL=cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INS CFLAGS1=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS=-g -O -I../include -DNOTPARMDECL $(CFLAGS1) -DDLB CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE +CFLAGS+=-DTIMED_DELAY CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" CFLAGS+=-DVAR_PLAYGROUND=\"$(HACKDIR)/var\" From a8172e1208bddca281ef97dc96e8234da15c7193 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 18:24:38 +0200 Subject: [PATCH 68/86] Fix unreferenced variable --- win/tty/wintty.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 27d53180a..acd1b86ad 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3212,7 +3212,7 @@ const char *str; int tty_nhgetch() { - int i, tmp; + int i; #ifdef UNIX /* kludge alert: Some Unix variants return funny values if getc() * is called, interrupted, and then called again. There @@ -3247,10 +3247,12 @@ tty_nhgetch() if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; #ifdef TTY_TILES_ESCCODES - /* hack to force output of the window select code */ - tmp = vt_tile_current_window; - vt_tile_current_window++; - print_vt_code2(AVTC_SELECT_WINDOW, tmp); + { + /* hack to force output of the window select code */ + int tmp = vt_tile_current_window; + vt_tile_current_window++; + print_vt_code2(AVTC_SELECT_WINDOW, tmp); + } #endif /* TTY_TILES_ESCCODES */ return i; } From 854fe40609daefc0709ef22c4c509825088eb15b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 18:27:34 +0200 Subject: [PATCH 69/86] Fix bz175: Pile mark is shown when potion is destroyed Original bug report: > When killing something that's carrying a potion, or death-drops a potion, > or stands on top of a potion, with a force bolt or a wand of striking, > "you hear something shatter" or "a potion of foo shatters" but the corpse > is inverse as if it's (still) a pile. Unfortunately the newsym() checks for already existing glyph, and the gbuf doesn't distinguish between object piles and single items, so newsym doesn't mark the location for update. This is a dirty hack to force the newsym to update the glyph. The glyph buffering should be revisited in a future version. --- include/extern.h | 1 + src/display.c | 15 +++++++++++++++ src/zap.c | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/include/extern.h b/include/extern.h index 70ce04b31..f45ca4b30 100644 --- a/include/extern.h +++ b/include/extern.h @@ -310,6 +310,7 @@ E void FDECL(map_location, (int, int, int)); E void FDECL(feel_newsym, (XCHAR_P, XCHAR_P)); E void FDECL(feel_location, (XCHAR_P, XCHAR_P)); E void FDECL(newsym, (int, int)); +E void FDECL(newsym_force, (int, int)); E void FDECL(shieldeff, (XCHAR_P, XCHAR_P)); E void FDECL(tmp_at, (int, int)); E void FDECL(swallowed, (int)); diff --git a/src/display.c b/src/display.c index 333ed4d5b..09fd943eb 100644 --- a/src/display.c +++ b/src/display.c @@ -1318,6 +1318,21 @@ static gbuf_entry gbuf[ROWNO][COLNO]; static char gbuf_start[ROWNO]; static char gbuf_stop[ROWNO]; +/* FIXME: This is a dirty hack, because newsym() doesn't distinguish + * between object piles and single objects, it doesn't mark the location + * for update. */ +void +newsym_force(x, y) +register int x, y; +{ + newsym(x,y); + gbuf[y][x].new = 1; + if (gbuf_start[y] > x) + gbuf_start[y] = x; + if (gbuf_stop[y] < x) + gbuf_stop[y] = x; +} + /* * Store the glyph in the 3rd screen for later flushing. */ diff --git a/src/zap.c b/src/zap.c index 6a695fbac..4f3dc5707 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1875,10 +1875,14 @@ struct obj *obj, *otmp; You_hear("a crumbling sound."); } } else { + int oox = obj->ox; + int ooy = obj->oy; if (context.mon_moving ? !breaks(obj, obj->ox, obj->oy) : !hero_breaks(obj, obj->ox, obj->oy, FALSE)) maybelearnit = FALSE; /* nothing broke */ + else + newsym_force(oox,ooy); res = 0; } if (maybelearnit) From c902b44b5b0c7be9b412265eb9ffbf7d1ec1c992 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 18:54:35 +0200 Subject: [PATCH 70/86] Document fixes --- doc/fixes36.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index c3b17ca0f..0077cc71b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -108,6 +108,7 @@ don't create globs of ooze/slime/pudding with bknown flag set so pre-known to be "uncursed" do allow globs with same curse/bless state to merge even when that state is known for one and unknown for the other; result will have bknown clear +fix pile mark after killing a monster carrying a potion which is destroyed Platform- and/or Interface-Specific Fixes From 9cfc0ac5d7bf2ce9d32f188d60c921deda243231 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 10 Jan 2016 14:42:06 -0800 Subject: [PATCH 71/86] getpos() 'm','M' and 'o','O' Always include the hero's location in the set of spots for 'm',&c to cycle through. This way the set will never be empty so checks for that can be dropped, and choosing initial index becomes trivial (set to 0, then increment to reach nearest spot of interest or decrement to reach farthest). Also, it makes it easier for player to see when successive 'm's,&c have been through all the interesting locations if there are multiple monsters or objects clumped near the last one in the cycle. --- src/do_name.c | 120 +++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 158189e39..80d2093fd 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1452064740 2016/01/06 07:19:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.84 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1452465671 2016/01/10 22:41:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.88 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -102,41 +102,51 @@ coord **arr_p; int *cnt_p; boolean do_mons; { - int x, y, pass, glyph, idx; - boolean wantedloc; + int x, y, pass, glyph, idx, + tail = (do_mons ? monnum_to_glyph(PM_LONG_WORM_TAIL) : 0), + boulder = (!do_mons ? objnum_to_glyph(BOULDER) : 0), + rock = (!do_mons ? objnum_to_glyph(ROCK) : 0); + /* + * We always include the hero's location even if there is no monster + * (invisible hero without see invisible) or object (usual case) + * displayed there. That way, the count will always be at least 1, + * and player has a visual indicator (cursor returns to hero's spot) + * highlighting when successive 'm's or 'o's have cycled all the way + * through all monsters or objects. + * + * Hero's spot will always sort to array[0] because it will always + * be the shortest distance (namely, 0 units) away from . + */ *cnt_p = idx = 0; for (pass = 0; pass < 2; pass++) { - if (pass) { - /* *cnt_p + 1: always allocate a non-zero amount */ - *arr_p = (coord *) alloc(sizeof (coord) * (*cnt_p + 1)); - if (!*cnt_p) { - /* needed for caller's mon[0].x,.y==u.ux,.uy check */ - (*arr_p)[0].x = (*arr_p)[0].y = 0; - break; - } - } for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { + /* TODO: if glyph is a pile glyph, convert to ordinary one + * in order to keep tail/boulder/rock check simple. + */ glyph = glyph_at(x, y); /* unlike '/M', this skips monsters revealed by - * warning glyphs and remembered invisible ones; - * TODO: skip worm tails, boulders and rocks - */ - wantedloc = (do_mons && glyph_is_monster(glyph) - || !do_mons && glyph_is_object(glyph)); - if (!wantedloc) continue; - if (!pass) { - ++*cnt_p; - } else { - (*arr_p)[idx].x = x; - (*arr_p)[idx].y = y; - ++idx; + warning glyphs and remembered invisible ones */ + if ((x == u.ux && y == u.uy) + || (do_mons ? (glyph_is_monster(glyph) && glyph != tail) + : (glyph_is_object(glyph) + && glyph != boulder && glyph != rock))) { + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; + } } } + + if (!pass) /* end of first pass */ + *arr_p = (coord *) alloc(sizeof (coord) * *cnt_p); + else /* end of second pass */ + qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu); } /* pass */ - if (*cnt_p) - qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu); } int @@ -283,51 +293,41 @@ const char *goal; show_goal_msg = TRUE; msg_given = TRUE; goto nxtc; - } else if (c == '@') { + } else if (c == '@') { /* return to hero's spot */ + /* reset 'm','M' and 'o','O'; otherwise, there's no way for player + to achieve that except by manually cycling through all spots */ + monidx = objidx = 0; cx = u.ux; cy = u.uy; goto nxtc; - } else if (c == 'm' || c == 'M') { + } else if (c == 'm' || c == 'M') { /* nearest or farthest monster */ if (!monarr) { gather_locs(&monarr, &moncount, TRUE); - /* when hero is first element (always, unless unseen), - we want first increment to reach 1 (nearest aside - from hero) or first decrement to reach moncount-1 - (farthest); if hero is not first element, we want - first increment to end up with 0 (nearest monster), - first decrement should still choose moncount-1 */ - monidx = (monarr[0].x == u.ux && monarr[0].y == u.uy) ? 0 - : (c == 'm') ? -1 : 0; + monidx = 0; /* monarr[0] is hero's spot */ } - if (moncount) { - if (c == 'm') { - monidx = (monidx + 1) % moncount; - } else { - if (--monidx < 0) - monidx = moncount - 1; - } - cx = monarr[monidx].x; - cy = monarr[monidx].y; - goto nxtc; + if (c == 'm') { + monidx = (monidx + 1) % moncount; + } else { + if (--monidx < 0) + monidx = moncount - 1; } - } else if (c == 'o' || c == 'O') { + cx = monarr[monidx].x; + cy = monarr[monidx].y; + goto nxtc; + } else if (c == 'o' || c == 'O') { /* nearest or farthest object */ if (!objarr) { gather_locs(&objarr, &objcount, FALSE); - /* ready for first increment to change to zero - or first decrement to change to objcount-1 */ - objidx = (c == 'o') ? -1 : 0; + objidx = 0; /* objarr[0] is hero's spot */ } - if (objcount) { - if (c == 'o') { - objidx = (objidx + 1) % objcount; - } else { - if (--objidx < 0) - objidx = objcount - 1; - } - cx = objarr[objidx].x; - cy = objarr[objidx].y; - goto nxtc; + if (c == 'o') { + objidx = (objidx + 1) % objcount; + } else { + if (--objidx < 0) + objidx = objcount - 1; } + cx = objarr[objidx].x; + cy = objarr[objidx].y; + goto nxtc; } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; From 0ee5d8ce4763dd2e5039295e4ec8fdad1da9f473 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 11 Jan 2016 21:07:33 +0200 Subject: [PATCH 72/86] Add getpos_coord option Allows showing the coordinate when picking a position on the map with '/' and autodescribe is on. This is another blind player request --- doc/Guidebook.mn | 5 +++++ doc/Guidebook.tex | 6 ++++++ include/flag.h | 6 ++++++ src/do_name.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/options.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 2d73781f5..44dc33b29 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -2125,6 +2125,11 @@ The default is to randomly pick an appropriate gender. If you prefix a `!' or ``no'' to the value, you can exclude that gender from being picked randomly. Cannot be set with the `O' command. Persistent. +.lp getpos_coord +When using the `/' command to look around on the map with +``autodescribe'' on, display coordinates after the description. +The value specified should be the first letter of one of the following: +absolute, cartesian, or none. Default is none. .lp "help " If more information is available for an object looked at with the `/' command, ask if you want to see it (default on). Turning help diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 53716a2a9..88a9d8eb6 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2559,6 +2559,12 @@ If you prefix `{\tt !}' or ``{\tt no}'' to the value, you can exclude that gender from being picked randomly. Cannot be set with the `{\tt O}' command. Persistent. %.lp +\item[\ib{getpos\verb+_+coord}] +When using the `{\tt /}' command to look around on the map with +``{\tt autodescribe}'' on, display coordinates after the description. +The value specified should be the first letter of one of the following: +absolute, cartesian, or none. Default is none. +%.lp \item[\ib{help}] If more information is available for an object looked at with the `{\tt /}' command, ask if you want to see it (default on). diff --git a/include/flag.h b/include/flag.h index 79da89f92..298825660 100644 --- a/include/flag.h +++ b/include/flag.h @@ -167,6 +167,11 @@ struct sysflag { * */ +/* values for iflags.getpos_coords */ +#define GPCOORDS_NONE 'n' +#define GPCOORDS_ABSOLUTE 'a' +#define GPCOORDS_CARTESIAN 'c' + struct instance_flags { /* stuff that really isn't option or platform related. They are * set and cleared during the game to control the internal @@ -185,6 +190,7 @@ struct instance_flags { boolean mon_polycontrol; /* debug: control monster polymorphs */ /* stuff that is related to options and/or user or platform preferences */ unsigned msg_history; /* hint: # of top lines to save */ + int getpos_coords; /* show coordinates when getting cursor position */ int menu_headings; /* ATR for menu headings */ int *opt_booldup; /* for duplication of boolean opts in config file */ int *opt_compdup; /* for duplication of compound opts in config file */ diff --git a/src/do_name.c b/src/do_name.c index 80d2093fd..3c86589c2 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -149,6 +149,34 @@ boolean do_mons; } /* pass */ } +char * +dxdy_to_dist_descr(dx,dy) +int dx,dy; +{ + static char buf[QBUFSZ]; + int d; + if (!dx && !dy) + Sprintf(buf, "here"); + else if ((d = xytod(dx,dy)) != -1) + Sprintf(buf, "%s", directionname(d)); + else { + char tmp[QBUFSZ]; + buf[0] = '\0'; + if (dy) { + Sprintf(tmp, "%i%c", abs(dy), (dy > 0) ? 's' : 'n'); + Strcat(buf, tmp); + } + if (dy && dx) + Strcat(buf, ","); + if (dx) { + Sprintf(tmp, "%i%c", abs(dx), (dx > 0) ? 'e' : 'w'); + Strcat(buf, tmp); + } + } + return buf; +} + + int getpos(ccp, force, goal) coord *ccp; @@ -192,12 +220,27 @@ const char *goal; coord cc; int sym = 0; char tmpbuf[BUFSZ]; + char outbuf[BUFSZ]; const char *firstmatch = NULL; + int dx,dy; cc.x = cx; cc.y = cy; if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { - pline1(firstmatch); + outbuf[0] = '\0'; + switch (iflags.getpos_coords) { + default: + break; + case GPCOORDS_CARTESIAN: + dx = cc.x - u.ux; + dy = cc.y - u.uy; + Sprintf(outbuf, " (%s)", dxdy_to_dist_descr(dx,dy)); + break; + case GPCOORDS_ABSOLUTE: + Sprintf(outbuf, " (%d,%d)", cc.x,cc.y); + break; + } + pline("%s%s", firstmatch, outbuf); curs(WIN_MAP, cx, cy); flush_screen(0); } diff --git a/src/options.c b/src/options.c index 8c47c6ae4..6ba023a3c 100644 --- a/src/options.c +++ b/src/options.c @@ -294,6 +294,7 @@ static struct Comp_Opt { DISP_IN_GAME }, /*WC*/ { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME }, { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME }, + { "getpos_coord", "show coordinates when getting cursor position", 1, SET_IN_GAME }, { "horsename", "the name of your (first) horse (e.g., horsename:Silver)", PL_PSIZ, DISP_IN_GAME }, { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/ @@ -685,6 +686,7 @@ initoptions_init() iflags.prevmsg_window = 's'; #endif iflags.menu_headings = ATR_INVERSE; + iflags.getpos_coords = GPCOORDS_NONE; /* hero's role, race, &c haven't been chosen yet */ flags.initrole = flags.initrace = flags.initgend = flags.initalign = @@ -2332,6 +2334,24 @@ boolean tinitial, tfrom_file; return; } + fullname = "getpos_coord"; + if (match_optname(opts, fullname, 6, TRUE)) { + if (duplicate) + complain_about_duplicate(opts, 1); + if (negated) { + iflags.getpos_coords = GPCOORDS_NONE; + return; + } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { + if (tolower(*op) == GPCOORDS_NONE + || tolower(*op) == GPCOORDS_CARTESIAN + || tolower(*op) == GPCOORDS_ABSOLUTE) { + iflags.getpos_coords = tolower(*op); + } else + badoption(opts); + } + return; + } + fullname = "warnings"; if (match_optname(opts, fullname, 5, TRUE)) { if (duplicate) @@ -4008,6 +4028,27 @@ boolean setinitial, setfromfile; free((genericptr_t) mode_pick); } destroy_nhwindow(tmpwin); + } else if (!strcmp("getpos_coord", optname)) { + menu_item *window_pick = (menu_item *) 0; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any = zeroany; + any.a_char = GPCOORDS_ABSOLUTE; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_ABSOLUTE, + 0, ATR_NONE, "absolute", MENU_UNSELECTED); + any.a_char = GPCOORDS_CARTESIAN; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_CARTESIAN, + 0, ATR_NONE, "cartesian", MENU_UNSELECTED); + any.a_char = GPCOORDS_NONE; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE, + 0, ATR_NONE, "none", MENU_UNSELECTED); + end_menu(tmpwin, "Select coordinate display when picking a position:"); + if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { + iflags.getpos_coords = window_pick->item.a_char; + free((genericptr_t) window_pick); + } + destroy_nhwindow(tmpwin); } else if (!strcmp("msg_window", optname)) { #ifdef TTY_GRAPHICS /* by Christian W. Cooper */ @@ -4755,6 +4796,11 @@ char *buf; Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m)); } else if (!strcmp(optname, "runmode")) { Sprintf(buf, "%s", runmodes[flags.runmode]); + } else if (!strcmp(optname, "getpos_coord")) { + Sprintf(buf, "%s", + (iflags.getpos_coords == GPCOORDS_ABSOLUTE) ? "absolute" + : (iflags.getpos_coords == GPCOORDS_CARTESIAN) ? "cartesian" + : "none"); } else if (!strcmp(optname, "scores")) { Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, flags.end_own ? "/own" : ""); From 6dd6584e21b29282bf16ddaef62647e8d4830364 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 11 Jan 2016 21:12:52 +0200 Subject: [PATCH 73/86] Add getpos_coord to fixes file --- doc/fixes36.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 0077cc71b..96c0ee768 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -156,6 +156,8 @@ additional tribute passages for The Colour of Magic, The Light Fantastic, compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use database entries for Cleaver, Sunsword, Frost and Fire brands, and polymorph trap +allow showing coordinates when picking a position on the map and + autodescribe option is on Platform- and/or Interface-Specific New Features From 99ee3546372c07c64f20fae68b892606547864ac Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 12 Jan 2016 08:20:13 +0200 Subject: [PATCH 74/86] Fix get_count: ^H should go left instead of backspacing a count --- src/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd.c b/src/cmd.c index 1b389f722..ee1db8602 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3893,7 +3893,7 @@ long *count; cnt = 0; else if (maxcount > 0 && cnt > maxcount) cnt = maxcount; - } else if (key == '\b' || key == STANDBY_erase_char) { + } else if (cnt && (key == '\b' || key == STANDBY_erase_char)) { cnt = cnt / 10; backspaced = TRUE; } else if (key == '\033') { From c5db7f57a3c0b75a1cb69fbd244beb3c9754204a Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 12 Jan 2016 02:15:35 -0800 Subject: [PATCH 75/86] X11 extended command menu Restore the ability to select extended commands by keystroke. The key translation stuff had gotten attached to the wrong widget. When using keys to highlight an entry in the extended command menu, don't reset the key-by-key handling so quickly. (On second and subsequent keystrokes, if you waited more than 0.5 second, the new key started picking an extended command from scratch rather than continuing the current one, making it pretty hard to disambiguate commands which have the same initial letter. Now the delay threshold is 2.5 seconds. In theory that should become a user- preference resource but I don't think it's worth the effort.) Display the help choice in response to '?'. Clean up the formatting of the top two buttons (dismiss + help). Start with a scroll bar if the menu is too big to fit on the screen. Prior to this, on OSX, the full menu would be constructed but any of it that was 'displayed' beneath the bottom of the screen was inaccessible because it couldn't be dragged higher and couldn't be resized to get a scroll bar (since the way to resize on OSX is by dragging the bottom right corner--which was off the screen). The problems I mentioned recently are still present: when scroll bar is present, I can click beneath it and it moves down, but neither dragging it up nor clicking above it will move it back up. Fortunately the recently implemented up and down arrows both work, even after clicking/dragging starts failing. There was a lot of trial and error involved here. Most of it eventually got phased out, but the mystery of 'defaultDistance' (which is reported to be 0 but is actually 4) remains. The screen height stuff at the end ought to be fixed up if someone can figure out how to get the width of a horizontal scroll bar or the height of a title bar. (I'm sure I used to know how to do the latter, but that was 25 or so years ago, and in Fortran with Xlib rather than Xt or Xaw....) --- win/X11/winmisc.c | 198 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 140 insertions(+), 58 deletions(-) diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 78e1b73b9..fa73f9980 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -1,11 +1,11 @@ -/* NetHack 3.6 winmisc.c $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ -/* Copyright (c) Dean Luick, 1992 */ +/* NetHack 3.6 winmisc.c $NHDT-Date: 1452593730 2016/01/12 10:15:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ */ +/* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Misc. popup windows: player selection and extended commands. * - * + Global functions: player_selection() and get_ext_cmd(). + * + Global functions: player_selection() and get_ext_cmd(). */ #ifndef SYSV @@ -727,6 +727,9 @@ Cardinal *num_params; if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; + } else if (ch == '?') { + extend_help(); + return; } else if (index("\033\n\r", ch)) { if (ch == '\033') { /* unselect while still visible */ @@ -745,8 +748,14 @@ Cardinal *num_params; return; } - /* too much time has elapsed */ - if ((xkey->time - ec_time) > 500) + /* + * If too much time has elapsed, treat current key as starting a new + * choice, otherwise it is a continuation of the choice in progress. + * Extra letters might be needed to disambiguate between choices + * ("ride" vs "rub", for instance), or player may just be typing in + * the whole word. + */ + if ((xkey->time - ec_time) > 2500) /* 2.5 seconds */ ec_active = FALSE; if (!ec_active) { @@ -816,21 +825,21 @@ init_extended_commands_popup() /* * Create a popup widget of the following form: * - * popup_label - * ----------- ------------ - * |left_name| |right_name| - * ----------- ------------ - * ------------------------ - * | name1 | - * ------------------------ - * ------------------------ - * | name2 | - * ------------------------ - * . - * . - * ------------------------ - * | nameN | - * ------------------------ + * popup_label + * ----------- ------------ + * |left_name| |right_name| + * ----------- ------------ + * ------------------------ + * | name1 | + * ------------------------ + * ------------------------ + * | name2 | + * ------------------------ + * . + * . + * ------------------------ + * | nameN | + * ------------------------ */ static Widget make_menu(popup_name, popup_label, popup_translations, left_name, @@ -854,15 +863,14 @@ Widget *formp; /* return */ int i; Arg args[8]; Cardinal num_args; - Dimension width, max_width; + Dimension width, other_width, max_width, border_width, + height, cumulative_height, screen_height; int distance, skip; - commands = (Widget *) alloc((unsigned) num_names * sizeof(Widget)); + commands = (Widget *) alloc((unsigned) num_names * sizeof (Widget)); num_args = 0; - XtSetArg(args[num_args], XtNallowShellResize, True); - num_args++; - + XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; popup = XtCreatePopupShell(popup_name, transientShellWidgetClass, toplevel, args, num_args); XtOverrideTranslations( @@ -871,60 +879,71 @@ Widget *formp; /* return */ num_args = 0; XtSetArg(args[num_args], XtNforceBars, False); num_args++; XtSetArg(args[num_args], XtNallowVert, True); num_args++; + XtSetArg(args[num_args], XtNtranslations, + XtParseTranslationTable(popup_translations)); num_args++; view = XtCreateManagedWidget("menuformview", viewportWidgetClass, popup, args, num_args); num_args = 0; - XtSetArg(args[num_args], XtNtranslations, - XtParseTranslationTable(popup_translations)); - num_args++; *formp = form = XtCreateManagedWidget("menuform", formWidgetClass, view, args, num_args); - /* Get the default distance between objects in the form widget. */ + /* + * Get the default distance between objects in the viewport widget. + * (Something is fishy here: 'distance' ends up being 0 but there + * is a non-zero gap between the borders of the internal widgets. + * It matches exactly the default value of 4 for defaultDistance.) + */ num_args = 0; - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance); - num_args++; + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance); num_args++; + XtSetArg(args[num_args], nhStr(XtNborderWidth), &border_width); num_args++; XtGetValues(view, args, num_args); + if (!distance) + distance = 4; /* * Create the label. */ num_args = 0; - XtSetArg(args[num_args], XtNborderWidth, 0); - num_args++; + XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; label = XtCreateManagedWidget(popup_label, labelWidgetClass, form, args, num_args); + cumulative_height = 0; + XtSetArg(args[0], XtNheight, &height); + XtGetValues(label, args, ONE); + cumulative_height += distance + height; /* no border for label */ + /* * Create the left button. */ num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfromVert), label); - num_args++; - /* - XtSetArg(args[num_args], nhStr(XtNshapeStyle), - XmuShapeRoundedRectangle); num_args++; - */ + XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; +#if 0 + XtSetArg(args[num_args], nhStr(XtNshapeStyle), + XmuShapeRoundedRectangle); num_args++; +#endif left = XtCreateManagedWidget(left_name, commandWidgetClass, form, args, num_args); XtAddCallback(left, XtNcallback, left_callback, (XtPointer) 0); - skip = 3 * distance; /* triple the spacing */ - if (!skip) - skip = 3; + skip = (distance < 4) ? 8 : 2 * distance; + + num_args = 0; + XtSetArg(args[0], XtNheight, &height); + XtGetValues(left, args, ONE); + cumulative_height += distance + height + 2 * border_width; /* * Create right button. */ num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); - num_args++; - XtSetArg(args[num_args], nhStr(XtNfromVert), label); - num_args++; - /* - XtSetArg(args[num_args], nhStr(XtNshapeStyle), - XmuShapeRoundedRectangle); num_args++; - */ + XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; + XtSetArg(args[num_args], nhStr(XtNhorizDistance), skip); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; +#if 0 + XtSetArg(args[num_args], nhStr(XtNshapeStyle), + XmuShapeRoundedRectangle); num_args++; +#endif right = XtCreateManagedWidget(right_name, commandWidgetClass, form, args, num_args); XtAddCallback(right, XtNcallback, right_callback, (XtPointer) 0); @@ -939,29 +958,33 @@ Widget *formp; /* return */ if (!widget_names[i]) continue; num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfromVert), above); - num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++; if (above == left) { /* if first, we are farther apart */ - XtSetArg(args[num_args], nhStr(XtNvertDistance), skip); - num_args++; - } + XtSetArg(args[num_args], nhStr(XtNvertDistance), skip); num_args++; + cumulative_height += skip; + } else + cumulative_height += distance; + cumulative_height += height + 2 * border_width; *curr = XtCreateManagedWidget(widget_names[i], commandWidgetClass, form, args, num_args); XtAddCallback(*curr, XtNcallback, name_callback, (XtPointer) i); above = *curr++; } + cumulative_height += distance; /* space at bottom of form */ /* - * Now find the largest width. Start with the width dismiss + help - * buttons, since they are adjacent. + * Now find the largest width. Start with width of left + right buttons + * ('dismiss' + 'help' or 'quit' + 'random'), since they are adjacent. */ XtSetArg(args[0], XtNwidth, &max_width); XtGetValues(left, args, ONE); XtSetArg(args[0], XtNwidth, &width); XtGetValues(right, args, ONE); - max_width = max_width + width + distance; + /* doesn't count leftmost 'distance + border_width' and + rightmost 'border_width + distance' since all entries have those */ + max_width = max_width + border_width + skip + border_width + width; /* Next, the title. */ XtSetArg(args[0], XtNwidth, &width); @@ -980,6 +1003,40 @@ Widget *formp; /* return */ curr++; } + /* + * Re-do the two side-by-side widgets to take up half the width each. + * + * With max_width and skip both having even values, we never have to + * tweak left or right to maybe be one pixel wider than the other. + */ + if (max_width % 2) + ++max_width; + XtSetArg(args[0], XtNwidth, &width); + XtGetValues(left, args, ONE); + XtSetArg(args[0], XtNwidth, &other_width); + XtGetValues(right, args, ONE); + if (width + border_width + skip / 2 < max_width / 2 + && other_width + border_width + skip / 2 < max_width / 2) { + /* both are narrower than half */ + width = other_width = max_width / 2 - border_width - skip / 2; + XtSetArg(args[0], XtNwidth, width); + XtSetValues(left, args, ONE); + XtSetArg(args[0], XtNwidth, other_width); + XtSetValues(right, args, ONE); + } else if (width + border_width + skip / 2 < max_width / 2) { + /* 'other_width' (right) is half or more */ + width = max_width - other_width - 2 * border_width - skip; + XtSetArg(args[0], XtNwidth, width); + XtSetValues(left, args, ONE); + } else if (other_width + border_width + skip / 2 < max_width / 2) { + /* 'width' (left) is half or more */ + other_width = max_width - width - 2 * border_width - skip; + XtSetArg(args[0], XtNwidth, other_width); + XtSetValues(right, args, ONE); + } else { + ; /* both are exactly half... */ + } + /* * Finally, set all of the single line widgets to the largest width. */ @@ -999,6 +1056,31 @@ Widget *formp; /* return */ else free((char *) commands); + /* + * We actually want height of topmost background window, which + * may or may not be the root window. + * + * On OSX, screen height includes the space taken up by the + * desktop title bar, which isn't accessible to applications + * unless the preference settings for X11 are changed to force + * full-screen mode (so by default, this 'screen_height' value + * ends up being bigger than the available size...). + */ + screen_height = XHeightOfScreen(XtScreen(popup)); + + /* + * If the menu's complete height is too big for the display, + * forcing the height to be smaller will cause the vertical + * scroll bar (enabled but not forced above) to be included. + */ + if (cumulative_height >= screen_height) { + /* trial and error: 25 is a guesstimate for scrollbar width on + width adjustment and for title bar height on height adjustment */ + num_args = 0; + XtSetArg(args[num_args], XtNwidth, max_width + 25); num_args++; + XtSetArg(args[num_args], XtNheight, screen_height - 25); num_args++; + XtSetValues(popup, args, num_args); + } XtRealizeWidget(popup); XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1); From a34d327159717ad2c7aa9e1d97feeb5046ef723c Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 12 Jan 2016 02:20:43 -0800 Subject: [PATCH 76/86] bit of X11 reformating Cleanup up the copyright notice in dialogs.c, and replace some tabs. --- win/X11/dialogs.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/win/X11/dialogs.c b/win/X11/dialogs.c index e05e7ad17..d7c24dd55 100644 --- a/win/X11/dialogs.c +++ b/win/X11/dialogs.c @@ -1,25 +1,24 @@ /* * Copyright 1991 University of Wisconsin-Madison * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting - * documentation, and that the name of the University of Wisconsin-Madison not - * be used in advertising or publicity pertaining to distribution of the + * documentation, and that the name of the University of Wisconsin-Madison + * not be used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. The University of * Wisconsin-Madison makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * - * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE - *FOR - * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Tim Theisen Department of Computer Sciences * tim@cs.wisc.edu University of Wisconsin-Madison @@ -32,24 +31,24 @@ * * + Make the cancel button optional. * + Put an #ifdef SPECIAL_CMAP around code to fix a colormap bug. - * We don't need it here. + * We don't need it here. * + Add the function positionpopup() from another part of ghostview - * to this code. + * to this code. * * Modified 2/93, Various. * + Added workaround for SYSV include problem. * + Changed the default width response text widget to be as wide as the - * window itself. Suggestion from David E. Wexelblat, dwex@goblin.org. + * window itself. Suggestion from David E. Wexelblat, dwex@goblin.org. * * Modified 5/2015, anonymous. * + Include nethack's lint.h to get nhStr() macro. * + Use nhStr() on string literals (or macros from - * that hide string literals) to cast away implicit 'const' in order - * to suppress "warning: assignment discards qualifers from pointer - * target type" issued by 'gcc -Wwrite-strings' as used by nethack. - * (For this file, always the second parameter to XtSetArg().) + * that hide string literals) to cast away implicit 'const' in order + * to suppress "warning: assignment discards qualifers from pointer + * target type" issued by 'gcc -Wwrite-strings' as used by nethack. + * (For this file, always the second parameter to XtSetArg().) * - * $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ + * $NHDT-Date: 1452594032 2016/01/12 10:20:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.7 $ */ #ifndef SYSV @@ -85,10 +84,10 @@ static const char cancel_accelerators[] = "#override\n\ :[: set() notify() unset()\n"; /* for keyboards w/o an ESC */ /* Create a dialog widget. It is just a form widget with - * a label prompt - * a text response - * an okay button - * an optional cancel button + * a label prompt + * a text response + * an okay button + * an optional cancel button */ Widget CreateDialog(parent, name, okay_callback, cancel_callback) From 7e01237dce5077651243d293d74006f7c1ede832 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 12 Jan 2016 17:50:32 -0800 Subject: [PATCH 77/86] getobj() magic marker candidate items When applying a magic marker, only list known blank scrolls and known blank spellbooks as likely candidates to write on. Accepts any scroll or book (but non-blank ones will get rejected by the writing code). Attempting to choose some other class of item yields "that is a silly thing to write on", same as before. This was requested during beta testing and I'd swear that I checked it in a long time ago, but it wasn't here. --- doc/fixes36.1 | 2 ++ src/invent.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 96c0ee768..a27392c57 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -109,6 +109,8 @@ don't create globs of ooze/slime/pudding with bknown flag set so pre-known to do allow globs with same curse/bless state to merge even when that state is known for one and unknown for the other; result will have bknown clear fix pile mark after killing a monster carrying a potion which is destroyed +only list known blank scrolls and known blank spellbooks as likely candidates + when choosing an item to write on for applied magic marker Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index 94ae77d7c..6bbd89ca5 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1134,6 +1134,9 @@ register const char *let, *word; /* worn armor or accessory covered by cursed worn armor */ || (taking_off(word) && inaccessible_equipment(otmp, (const char *) 0, TRUE)) + || (!strcmp(word, "write on") + && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER) + || !otmp->dknown || !objects[otyp].oc_name_known)) ) { /* acceptable but not listed as likely candidate */ foo--; @@ -1160,6 +1163,11 @@ register const char *let, *word; if (!foo && !allowall && !allownone) { You("don't have anything %sto %s.", foox ? "else " : "", word); return (struct obj *) 0; + } else if (!strcmp(word, "write on")) { /* ugly check for magic marker */ + /* we wanted all scrolls and books in altlets[], but that came with + 'allowall' which we don't want since it prevents "silly thing" + result if anything other than scroll or spellbook is chosen */ + allowall = FALSE; } for (;;) { cnt = 0; From 04c39f9e91505379250f1a42934b1a3948f77610 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 12 Jan 2016 18:00:43 -0800 Subject: [PATCH 78/86] silly thing bit Simplify some conditionally excluded, obsolete but not yet discarded code. This is something else I thought I'd checked in a long time ago. I must have clobbered pending changes to invent.c at some point. --- src/invent.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/invent.c b/src/invent.c index 6bbd89ca5..6a2a910bd 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1450306195 2015/12/16 22:49:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.180 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1452650438 2016/01/13 02:00:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.188 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1325,7 +1325,7 @@ struct obj *otmp; #if 1 /* 'P','R' vs 'W','T' handling is obsolete */ nhUse(otmp); #else - const char *s1, *s2, *s3, *what; + const char *s1, *s2, *s3; int ocls = otmp->oclass, otyp = otmp->otyp; s1 = s2 = s3 = 0; @@ -1344,14 +1344,10 @@ struct obj *otmp; else if (!strcmp(word, "take off")) s1 = "R", s2 = "remove", s3 = ""; } - if (s1) { - what = "that"; - /* quantity for armor and accessory objects is always 1, - but some things should be referred to as plural */ - if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp)) - what = "those"; - pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); - } else + if (s1) + pline("Use the '%s' command to %s %s%s.", s1, s2, + !is_plural(otmp) ? "that" : "those", s3); + else #endif pline(silly_thing_to, word); } From 32a4859e5b7be49e49de2c81c0e72ec17b673d70 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 12 Jan 2016 23:43:28 -0500 Subject: [PATCH 79/86] show deafness indicator on status line May as well show a deafness indicator. --- include/botl.h | 3 ++- src/apply.c | 3 ++- src/botl.c | 9 ++++++++- src/cmd.c | 3 ++- src/eat.c | 8 ++++++-- src/music.c | 3 ++- src/potion.c | 5 ++--- src/timeout.c | 5 ++++- src/trap.c | 4 +++- 9 files changed, 31 insertions(+), 12 deletions(-) diff --git a/include/botl.h b/include/botl.h index 8945fa293..994b41009 100644 --- a/include/botl.h +++ b/include/botl.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.h $NHDT-Date: 1433105378 2015/05/31 20:49:38 $ $NHDT-Branch: status_hilite $:$NHDT-Revision: 1.14 $ */ +/* NetHack 3.6 botl.h $NHDT-Date: 1452660165 2016/01/13 04:42:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Michael Allison, 2003 */ /* NetHack may be freely redistributed. See license for details. */ @@ -69,6 +69,7 @@ BL_EXP, BL_CONDITION }; #define BL_MASK_HALLU 0x00000010L #define BL_MASK_STUNNED 0x00000020L #define BL_MASK_SLIMED 0x00000040L +#define BL_MASK_DEAF 0x00000080L /* clang-format on */ #define REASSESS_ONLY TRUE diff --git a/src/apply.c b/src/apply.c index 0136421d3..339f7f6d0 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 apply.c $NHDT-Date: 1450582748 2015/12/20 03:39:08 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.217 $ */ +/* NetHack 3.6 apply.c $NHDT-Date: 1452660177 2016/01/13 04:42:57 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.219 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1780,6 +1780,7 @@ struct obj *obj; if (Deaf) /* make_deaf() won't give feedback when already deaf */ pline("Nothing seems to happen."); make_deaf((HDeaf & TIMEOUT) + lcount, TRUE); + context.botl = TRUE; break; } return; diff --git a/src/botl.c b/src/botl.c index 422f6d4ef..261686a87 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1447978683 2015/11/20 00:18:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.69 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1452660188 2016/01/13 04:43:08 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -122,6 +122,8 @@ bot2() Sprintf(nb = eos(nb), " Hallu"); if (Slimed) Sprintf(nb = eos(nb), " Slime"); + if (Deaf) + Sprintf(nb = eos(nb), " Df"); if (cap > UNENCUMBERED) Sprintf(nb = eos(nb), " %s", enc_stat[cap]); curs(WIN_STATUS, 1, 1); @@ -543,6 +545,11 @@ bot() else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_BLIND; + if (Deaf) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_DEAF; + else + blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_DEAF; + if (Confusion) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_CONF; else diff --git a/src/cmd.c b/src/cmd.c index ee1db8602..47cdf8a2e 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1452123457 2016/01/06 23:37:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.216 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1452660189 2016/01/13 04:43:09 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.219 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1140,6 +1140,7 @@ wiz_intrinsic(VOID_ARGS) if (!strcmp(intrinsics[i],"deafness")) { You("go deaf."); incr_itimeout(&HDeaf, 30); + context.botl = TRUE; } } else pline("Unavailable command '%s'.", diff --git a/src/eat.c b/src/eat.c index 13a394405..265a868c3 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 eat.c $NHDT-Date: 1451086430 2015/12/25 23:33:50 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.157 $ */ +/* NetHack 3.6 eat.c $NHDT-Date: 1452660191 2016/01/13 04:43:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.161 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1479,8 +1479,10 @@ int Hear_again(VOID_ARGS) { /* Chance of deafness going away while fainted/sleeping/etc. */ - if (!rn2(2)) + if (!rn2(2)) { make_deaf(0L, FALSE); + context.botl = TRUE; + } return 0; } @@ -1514,6 +1516,7 @@ struct obj *obj; where = (u.usteed) ? "saddle" : surface(u.ux, u.uy); pline_The("world spins and %s %s.", what, where); incr_itimeout(&HDeaf, duration); + context.botl = TRUE; nomul(-duration); multi_reason = "unconscious from rotten food"; nomovemsg = "You are conscious again."; @@ -2839,6 +2842,7 @@ boolean incr; stop_occupation(); You("faint from lack of food."); incr_itimeout(&HDeaf, duration); + context.botl = TRUE; nomul(-duration); multi_reason = "fainted from lack of food"; nomovemsg = "You regain consciousness."; diff --git a/src/music.c b/src/music.c index 73b855bc1..f21a19483 100644 --- a/src/music.c +++ b/src/music.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 music.c $NHDT-Date: 1446808448 2015/11/06 11:14:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */ +/* NetHack 3.6 music.c $NHDT-Date: 1452660194 2016/01/13 04:43:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -567,6 +567,7 @@ struct obj *instr; awaken_monsters(u.ulevel * 40); incr_itimeout(&HDeaf, rn1(20, 30)); exercise(A_WIS, FALSE); + context.botl = TRUE; break; default: impossible("What a weird instrument (%d)!", instr->otyp); diff --git a/src/potion.c b/src/potion.c index c18c560b9..2a54d5fa1 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 potion.c $NHDT-Date: 1450667491 2015/12/21 03:11:31 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.124 $ */ +/* NetHack 3.6 potion.c $NHDT-Date: 1452660195 2016/01/13 04:43:15 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.126 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -410,8 +410,7 @@ boolean talk; You("are unable to hear anything."); toggled = TRUE; } - /* deafness isn't presently shown on status line, but - request a status update in case that changes someday */ + /* request a status update */ if (toggled) context.botl = TRUE; diff --git a/src/timeout.c b/src/timeout.c index e50ae39b2..7370b8b05 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 timeout.c $NHDT-Date: 1446861771 2015/11/07 02:02:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */ +/* NetHack 3.6 timeout.c $NHDT-Date: 1452660198 2016/01/13 04:43:18 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.64 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -345,6 +345,7 @@ nh_timeout() case DEAF: set_itimeout(&HDeaf, 1L); make_deaf(0L, TRUE); + context.botl = TRUE; if (!Deaf) stop_occupation(); break; @@ -443,6 +444,7 @@ boolean wakeup_msg; /* caller can follow with a direct call to Hear_again() if there's a need to override this when wakeup_msg is true */ incr_itimeout(&HDeaf, how_long); + context.botl = TRUE; afternmv = Hear_again; /* this won't give any messages */ } /* early wakeup from combat won't be possible until next monster turn */ @@ -1288,6 +1290,7 @@ do_storms() /* Even if already deaf, we sense the thunder's vibrations. */ pline("Kaboom!!! Boom!! Boom!!"); incr_itimeout(&HDeaf, rn1(20, 30)); + context.botl = TRUE; if (!u.uinvulnerable) { stop_occupation(); nomul(-3); diff --git a/src/trap.c b/src/trap.c index 71700c6c8..80f638e90 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1452039453 2016/01/06 00:17:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.253 $ */ +/* NetHack 3.6 trap.c $NHDT-Date: 1452660199 2016/01/13 04:43:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.255 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3066,10 +3066,12 @@ domagictrap() if (!Deaf) { You_hear("a deafening roar!"); incr_itimeout(&HDeaf, rn1(20, 30)); + context.botl = TRUE; } else { /* magic vibrations still hit you */ You_feel("rankled."); incr_itimeout(&HDeaf, rn1(5, 15)); + context.botl = TRUE; } while (cnt--) (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); From fc9cf8cf8902639952f30880da855f2676c0ef56 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Jan 2016 00:12:31 -0500 Subject: [PATCH 80/86] update fixes36.1 --- doc/fixes36.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a27392c57..eb93efc73 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -160,6 +160,7 @@ database entries for Cleaver, Sunsword, Frost and Fire brands, and polymorph trap allow showing coordinates when picking a position on the map and autodescribe option is on +add a status line deafness indicator Platform- and/or Interface-Specific New Features From 5f6c0bd04a8cf3c87a4357d63b76fccf56b841a7 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 12 Jan 2016 23:10:31 -0800 Subject: [PATCH 81/86] getpos autodescribe Move the details of autodescribe out of getpos into a separate routine. I think 'cartesian' mode should be renamed 'compass' mode, and 'absolute' mode perhaps should be 'map' mode. And we should have a new 'screen' mode which shows rows,columns (1..N rather than 0..N-1). For tty, row is line+2; message and prompting "window" is row 1, line 0 of map is row 2. Columns are straightforward since column 0 of the map isn't used for map display: column 1 of map is column 1 of screen. Non-tty mostly shouldn't care and might as well use the same conversion. --- src/do_name.c | 98 ++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 3c86589c2..aca4df3d2 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1452465671 2016/01/10 22:41:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.88 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1452669022 2016/01/13 07:10:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.90 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,7 +8,8 @@ STATIC_DCL char *NDECL(nextmbuf); STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *)); STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *)); -STATIC_OVL void FDECL(gather_locs, (coord **, int *, BOOLEAN_P)); +STATIC_DCL void FDECL(gather_locs, (coord **, int *, BOOLEAN_P)); +STATIC_DCL void FDECL(auto_describe, (int, int)); STATIC_DCL void NDECL(do_mname); STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *)); STATIC_DCL void FDECL(do_oname, (struct obj *)); @@ -143,39 +144,74 @@ boolean do_mons; } if (!pass) /* end of first pass */ - *arr_p = (coord *) alloc(sizeof (coord) * *cnt_p); + *arr_p = (coord *) alloc(*cnt_p * sizeof (coord)); else /* end of second pass */ qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu); } /* pass */ } char * -dxdy_to_dist_descr(dx,dy) -int dx,dy; +dxdy_to_dist_descr(dx, dy) +int dx, dy; { - static char buf[QBUFSZ]; - int d; - if (!dx && !dy) + /* [12] suffices, but guard against long translation for direction-name */ + static char buf[20]; + int dst; + + if (!dx && !dy) { Sprintf(buf, "here"); - else if ((d = xytod(dx,dy)) != -1) - Sprintf(buf, "%s", directionname(d)); - else { - char tmp[QBUFSZ]; + } else if ((dst = xytod(dx, dy)) != -1) { + /* explicit direction; 'one step' is implicit */ + Sprintf(buf, "%s", directionname(dst)); + } else { buf[0] = '\0'; + /* 9999: protect buf[] against overflow caused by invalid values */ if (dy) { - Sprintf(tmp, "%i%c", abs(dy), (dy > 0) ? 's' : 'n'); - Strcat(buf, tmp); + if (abs(dy) > 9999) + dy = sgn(dy) * 9999; + Sprintf(eos(buf), "%d%c", abs(dy), (dy > 0) ? 's' : 'n'); } if (dy && dx) - Strcat(buf, ","); + strkitten(buf, ','); if (dx) { - Sprintf(tmp, "%i%c", abs(dx), (dx > 0) ? 'e' : 'w'); - Strcat(buf, tmp); + if (abs(dx) > 9999) + dx = sgn(dx) * 9999; + Sprintf(eos(buf), "%d%c", abs(dx), (dx > 0) ? 'e' : 'w'); } } return buf; } +STATIC_OVL void +auto_describe(cx, cy) +int cx, cy; +{ + coord cc; + int sym = 0, dx, dy; + char tmpbuf[BUFSZ]; + const char *firstmatch = "unknown"; + + cc.x = cx; + cc.y = cy; + if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { + tmpbuf[0] = '\0'; + switch (iflags.getpos_coords) { + default: + break; + case GPCOORDS_CARTESIAN: + dx = cc.x - u.ux; + dy = cc.y - u.uy; + Sprintf(tmpbuf, " (%s)", dxdy_to_dist_descr(dx, dy)); + break; + case GPCOORDS_ABSOLUTE: + Sprintf(tmpbuf, " (%d,%d)", cc.x, cc.y); + break; + } + pline("%s%s", firstmatch, tmpbuf); + curs(WIN_MAP, cx, cy); + flush_screen(0); + } +} int getpos(ccp, force, goal) @@ -217,33 +253,7 @@ const char *goal; flush_screen(0); show_goal_msg = FALSE; } else if (iflags.autodescribe && !msg_given && !hilite_state) { - coord cc; - int sym = 0; - char tmpbuf[BUFSZ]; - char outbuf[BUFSZ]; - const char *firstmatch = NULL; - int dx,dy; - - cc.x = cx; - cc.y = cy; - if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { - outbuf[0] = '\0'; - switch (iflags.getpos_coords) { - default: - break; - case GPCOORDS_CARTESIAN: - dx = cc.x - u.ux; - dy = cc.y - u.uy; - Sprintf(outbuf, " (%s)", dxdy_to_dist_descr(dx,dy)); - break; - case GPCOORDS_ABSOLUTE: - Sprintf(outbuf, " (%d,%d)", cc.x,cc.y); - break; - } - pline("%s%s", firstmatch, outbuf); - curs(WIN_MAP, cx, cy); - flush_screen(0); - } + auto_describe(cx, cy); } c = nh_poskey(&tx, &ty, &sidx); From ef3ce49dd4a7ee07df4374bdd65f269cfa7d0024 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 13 Jan 2016 10:22:41 +0200 Subject: [PATCH 82/86] Make getpos monster/object coord picker deterministic ...and make it pick coordinates top-left to bottom-right. --- src/do_name.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index aca4df3d2..bd6d5e195 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -88,10 +88,13 @@ const void *b; dx = u.ux - c1->x; dy = u.uy - c1->y; - dist_1 = dx * dx + dy * dy; + dist_1 = max(abs(dx), abs(dy)); dx = u.ux - c2->x; dy = u.uy - c2->y; - dist_2 = dx * dx + dy * dy; + dist_2 = max(abs(dx), abs(dy)); + + if (dist_1 == dist_2) + return (c1->y != c2->y) ? (c1->y - c2->y) : (c1->x - c2->x); return dist_1 - dist_2; } From c49490dfd4bfb4e9a64359f13eaee86d6d92305c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 13 Jan 2016 12:21:27 +0200 Subject: [PATCH 83/86] Rename getpos_coord values to "compass" and "map" --- doc/Guidebook.mn | 2 +- doc/Guidebook.tex | 2 +- include/flag.h | 6 +++--- src/do_name.c | 9 ++++----- src/options.c | 20 ++++++++++---------- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 44dc33b29..bf9bc56bd 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -2129,7 +2129,7 @@ Cannot be set with the `O' command. Persistent. When using the `/' command to look around on the map with ``autodescribe'' on, display coordinates after the description. The value specified should be the first letter of one of the following: -absolute, cartesian, or none. Default is none. +compass, map, or none. Default is none. .lp "help " If more information is available for an object looked at with the `/' command, ask if you want to see it (default on). Turning help diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 88a9d8eb6..988367732 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2563,7 +2563,7 @@ Cannot be set with the `{\tt O}' command. Persistent. When using the `{\tt /}' command to look around on the map with ``{\tt autodescribe}'' on, display coordinates after the description. The value specified should be the first letter of one of the following: -absolute, cartesian, or none. Default is none. +compass, map, or none. Default is none. %.lp \item[\ib{help}] If more information is available for an object looked at diff --git a/include/flag.h b/include/flag.h index 298825660..ac175880b 100644 --- a/include/flag.h +++ b/include/flag.h @@ -168,9 +168,9 @@ struct sysflag { */ /* values for iflags.getpos_coords */ -#define GPCOORDS_NONE 'n' -#define GPCOORDS_ABSOLUTE 'a' -#define GPCOORDS_CARTESIAN 'c' +#define GPCOORDS_NONE 'n' +#define GPCOORDS_MAP 'm' +#define GPCOORDS_COMPASS 'c' struct instance_flags { /* stuff that really isn't option or platform related. They are diff --git a/src/do_name.c b/src/do_name.c index bd6d5e195..8f0768e3b 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -172,10 +172,9 @@ int dx, dy; if (dy) { if (abs(dy) > 9999) dy = sgn(dy) * 9999; - Sprintf(eos(buf), "%d%c", abs(dy), (dy > 0) ? 's' : 'n'); + Sprintf(eos(buf), "%d%c%s", abs(dy), (dy > 0) ? 's' : 'n', + dx ? "," : ""); } - if (dy && dx) - strkitten(buf, ','); if (dx) { if (abs(dx) > 9999) dx = sgn(dx) * 9999; @@ -201,12 +200,12 @@ int cx, cy; switch (iflags.getpos_coords) { default: break; - case GPCOORDS_CARTESIAN: + case GPCOORDS_COMPASS: dx = cc.x - u.ux; dy = cc.y - u.uy; Sprintf(tmpbuf, " (%s)", dxdy_to_dist_descr(dx, dy)); break; - case GPCOORDS_ABSOLUTE: + case GPCOORDS_MAP: Sprintf(tmpbuf, " (%d,%d)", cc.x, cc.y); break; } diff --git a/src/options.c b/src/options.c index 6ba023a3c..7d6ddc357 100644 --- a/src/options.c +++ b/src/options.c @@ -2343,8 +2343,8 @@ boolean tinitial, tfrom_file; return; } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { if (tolower(*op) == GPCOORDS_NONE - || tolower(*op) == GPCOORDS_CARTESIAN - || tolower(*op) == GPCOORDS_ABSOLUTE) { + || tolower(*op) == GPCOORDS_COMPASS + || tolower(*op) == GPCOORDS_MAP) { iflags.getpos_coords = tolower(*op); } else badoption(opts); @@ -4034,12 +4034,12 @@ boolean setinitial, setfromfile; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; - any.a_char = GPCOORDS_ABSOLUTE; - add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_ABSOLUTE, - 0, ATR_NONE, "absolute", MENU_UNSELECTED); - any.a_char = GPCOORDS_CARTESIAN; - add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_CARTESIAN, - 0, ATR_NONE, "cartesian", MENU_UNSELECTED); + any.a_char = GPCOORDS_COMPASS; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMPASS, + 0, ATR_NONE, "compass", MENU_UNSELECTED); + any.a_char = GPCOORDS_MAP; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_MAP, + 0, ATR_NONE, "map", MENU_UNSELECTED); any.a_char = GPCOORDS_NONE; add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE, 0, ATR_NONE, "none", MENU_UNSELECTED); @@ -4798,8 +4798,8 @@ char *buf; Sprintf(buf, "%s", runmodes[flags.runmode]); } else if (!strcmp(optname, "getpos_coord")) { Sprintf(buf, "%s", - (iflags.getpos_coords == GPCOORDS_ABSOLUTE) ? "absolute" - : (iflags.getpos_coords == GPCOORDS_CARTESIAN) ? "cartesian" + (iflags.getpos_coords == GPCOORDS_MAP) ? "map" + : (iflags.getpos_coords == GPCOORDS_COMPASS) ? "compass" : "none"); } else if (!strcmp(optname, "scores")) { Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, From 1dd37b7fca1c2e582a281b76348d068d292a6d72 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 13 Jan 2016 20:24:40 +0200 Subject: [PATCH 84/86] Make status hilites use same color string matching as menucolors --- doc/fixes36.1 | 1 + include/extern.h | 1 + src/botl.c | 15 ++------------- src/options.c | 35 ++++++++++++++++++++++------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index eb93efc73..4f2e0807f 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -111,6 +111,7 @@ do allow globs with same curse/bless state to merge even when that state is fix pile mark after killing a monster carrying a potion which is destroyed only list known blank scrolls and known blank spellbooks as likely candidates when choosing an item to write on for applied magic marker +make status hilites use same color names as menucolors Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index f45ca4b30..d0789f205 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1659,6 +1659,7 @@ E struct symparse *FDECL(match_sym, (char *)); E void NDECL(set_playmode); E int FDECL(sym_val, (char *)); E const char *FDECL(clr2colorname, (int)); +E int FDECL(match_str2clr, (char *)); E boolean FDECL(add_menu_coloring, (char *)); E boolean FDECL(get_menu_coloring, (char *, int *, int *)); E void NDECL(free_menu_coloring); diff --git a/src/botl.c b/src/botl.c index 261686a87..29aaf3839 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1214,21 +1214,10 @@ boolean from_configfile; } else if (strcmpi(how, "normal") == 0) { normal[i] = TRUE; } else { - int k; - char colorname[BUFSZ]; - for (k = 0; k < CLR_MAX; ++k) { - /* we have to make a copy to change space to dash */ - (void) strcpy(colorname, c_obj_colors[k]); - for (tmp = index(colorname, ' '); tmp; - tmp = index(colorname, ' ')) - *tmp = '-'; - if (strcmpi(how, colorname) == 0) { - coloridx[i] = k; - break; - } - } + int k = match_str2clr(how); if (k >= CLR_MAX) return FALSE; + coloridx[i] = k; } } diff --git a/src/options.c b/src/options.c index 7d6ddc357..d1869576f 100644 --- a/src/options.c +++ b/src/options.c @@ -1274,6 +1274,26 @@ int clr; return (char *) 0; } +int +match_str2clr(str) +char *str; +{ + int i, c = NO_COLOR; + + /* allow "lightblue", "light blue", and "light-blue" to match "light blue" + (also junk like "_l i-gh_t---b l u e" but we won't worry about that); + also copes with trailing space; mungspaces removed any leading space */ + for (i = 0; i < SIZE(colornames); i++) + if (colornames[i].name + && fuzzymatch(str, colornames[i].name, " -_", TRUE)) { + c = colornames[i].color; + break; + } + if (i == SIZE(colornames) && (*str >= '0' && *str <= '9')) + c = atoi(str); + return c; +} + const char * attr2attrname(attr) int attr; @@ -1563,19 +1583,8 @@ char *str; if ((amp = index(tmps, '&')) != 0) *amp = '\0'; - /* allow "lightblue", "light blue", and "light-blue" to match "light blue" - (also junk like "_l i-gh_t---b l u e" but we won't worry about that); - also copes with trailing space; mungspaces removed any leading space */ - for (i = 0; i < SIZE(colornames); i++) - if (colornames[i].name - && fuzzymatch(tmps, colornames[i].name, " -_", TRUE)) { - c = colornames[i].color; - break; - } - if (i == SIZE(colornames) && (*tmps >= '0' && *tmps <= '9')) - c = atoi(tmps); - - if (c > 15) + c = match_str2clr(tmps); + if (c >= CLR_MAX) return FALSE; if (amp) { From 5acb659076a40809c463d031a02ba71ac9a6a4d2 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 13 Jan 2016 20:35:06 +0200 Subject: [PATCH 85/86] Add more color aliases for menucolors and statushilites --- src/options.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/options.c b/src/options.c index d1869576f..58a6f281f 100644 --- a/src/options.c +++ b/src/options.c @@ -1242,6 +1242,11 @@ static const struct { { "light cyan", CLR_BRIGHT_CYAN }, { "white", CLR_WHITE }, { NULL, CLR_BLACK }, /* everything after this is an alias */ + { "transparent", NO_COLOR }, + { "nocolor", NO_COLOR }, + { "purple", CLR_MAGENTA }, + { "light purple", CLR_BRIGHT_MAGENTA }, + { "bright purple", CLR_BRIGHT_MAGENTA }, { "grey", CLR_GRAY }, { "bright red", CLR_ORANGE }, { "bright green", CLR_BRIGHT_GREEN }, From fa20ef382d389eb214e643b86a3638975cc2d4a5 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 13 Jan 2016 19:13:10 -0800 Subject: [PATCH 86/86] status line update Adding deafness to the status line spurred me on to something I've wanted to do for a long time. This adds 'Stone' and 'Strngl' as new status conditions, and moves the five fatal ones: "Stone Slime Strngl FoodPois TermIll" to the front of the status list since information about them is more important than any of the others. "Ill" has been renamed "TermIll"; "Df" has been renamed "Deaf"; "Lev", "Fly", and "Ride" are three additional new conditions, with Lev and Fly being mutually exclusive. After the fatal ones, the order of the rest is now Blind Deaf Stun Conf Hallu Lev Fly Ride To handle the longer potential status line, the basic bot2() is now smarter. If the line is wider than the map, 'T:moves' is moved from the middle to the end. If the line without time is still wider than the map, then experience (HD if polyd, Xp:M/nnnnnn is showexp is on, or Exp:M) is moved in front of time at the end. If the line without experience and time is still wider than the map, dungeon level plus gold is moved from the beginning to be in front of experience. The fields are just reordered, not truncated, so if the interface code can display lines wider than the map they'll retain the extra info. The gist is than health and associated fields (Hp, Pw, Ac) get first priority, status conditions get second priority, then the rest. In the usual case where there aren't many conditions, status display is the same as it has been in the past. STATUS_VIA_WINDOWPORT has been updated too, and it builds for tty and X11. But the bot2() revision to reorder sections has not been implemented for that. win/win32/mswproc.c has been updated but not tested. STATUS_VIA_WINDOWPORT without STATUS_HILITES had several compile problems; now fixed for core and tty. STATUS_VIA_WINDOWPORT with STATUS_HILITES has not been tested. --- doc/fixes36.1 | 4 +- include/botl.h | 43 +++-- src/botl.c | 409 +++++++++++++++++++++++++------------------- src/do_wear.c | 6 +- src/polyself.c | 5 +- src/potion.c | 39 ++--- src/steed.c | 9 +- src/trap.c | 2 + src/windows.c | 36 ++-- win/tty/wintty.c | 97 +++++++---- win/win32/mswproc.c | 59 ++++--- 11 files changed, 421 insertions(+), 288 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 4f2e0807f..bcc189206 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -155,13 +155,13 @@ poison breath leaves a trail of poison gas allow knife and stiletto as possible tin opening tools wizard mode #wizintrinsic command additional tribute passages for The Colour of Magic, The Light Fantastic, - Equal Rites, Snuff, and Raising Steam + Equal Rites, Mort, Snuff, and Raising Steam compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use database entries for Cleaver, Sunsword, Frost and Fire brands, and polymorph trap allow showing coordinates when picking a position on the map and autodescribe option is on -add a status line deafness indicator +new status line conditions Stone Strngl Deaf Lev Fly Ride Platform- and/or Interface-Specific New Features diff --git a/include/botl.h b/include/botl.h index 994b41009..e9c5644bb 100644 --- a/include/botl.h +++ b/include/botl.h @@ -9,14 +9,22 @@ * than COLNO * * longest practical second status line at the moment is - * Astral Plane $:12345 HP:700(700) Pw:111(111) AC:-127 Xp:30/123456789 - * T:123456 Satiated Conf FoodPois Ill Blind Stun Hallu Overloaded - * -- or somewhat over 130 characters +Astral Plane \GXXXXNNNN:123456 HP:1000(1000) Pw:111(111) AC:-127 + Xp:30/123456789 T:123456 Stone Slime Strngl FoodPois TermIll + Satiated Overloaded Blind Deaf Stun Conf Hallu Lev Ride + * -- or a bit under 185 characters. '$' gets encoded even when it + * could be used as-is. The first five status conditions are fatal + * so it's rare to have more than one at a time. + * + * When the full line is wider than the map, the basic status line + * formatting will move less important fields to the end, so if/when + * truncation is necessary, it will chop off the least significant + * information. */ -#if COLNO <= 140 -#define MAXCO 160 +#if COLNO <= 160 +#define MAXCO 200 #else -#define MAXCO (COLNO + 20) +#define MAXCO (COLNO + 40) #endif #ifdef STATUS_VIA_WINDOWPORT @@ -53,23 +61,28 @@ enum statusfields { BL_FLUSH = -1, BL_TITLE = 0, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION }; +#endif #define MAXBLSTATS BL_CONDITION+1 #define BEFORE 0 #define NOW 1 -#endif /* Boolean condition bits for the condition mask */ /* clang-format off */ -#define BL_MASK_BLIND 0x00000001L -#define BL_MASK_CONF 0x00000002L -#define BL_MASK_FOODPOIS 0x00000004L -#define BL_MASK_ILL 0x00000008L -#define BL_MASK_HALLU 0x00000010L -#define BL_MASK_STUNNED 0x00000020L -#define BL_MASK_SLIMED 0x00000040L -#define BL_MASK_DEAF 0x00000080L +#define BL_MASK_STONE 0x00000001L +#define BL_MASK_SLIME 0x00000002L +#define BL_MASK_STRNGL 0x00000004L +#define BL_MASK_FOODPOIS 0x00000008L +#define BL_MASK_TERMILL 0x00000010L +#define BL_MASK_BLIND 0x00000020L +#define BL_MASK_DEAF 0x00000040L +#define BL_MASK_STUN 0x00000080L +#define BL_MASK_CONF 0x00000100L +#define BL_MASK_HALLU 0x00000200L +#define BL_MASK_LEV 0x00000400L +#define BL_MASK_FLY 0x00000800L +#define BL_MASK_RIDE 0x00001000L /* clang-format on */ #define REASSESS_ONLY TRUE diff --git a/src/botl.c b/src/botl.c index 29aaf3839..49cb38154 100644 --- a/src/botl.c +++ b/src/botl.c @@ -78,54 +78,135 @@ bot1() STATIC_OVL void bot2() { - char newbot2[MAXCO]; + char newbot2[MAXCO], /* MAXCO: botl.h */ + /* dungeon location (and gold), hero health (HP, PW, AC), + experience (HD if poly'd, else Exp level and maybe Exp points), + time (in moves), varying number of status conditions */ + dloc[QBUFSZ], hlth[QBUFSZ], expr[QBUFSZ], tmmv[QBUFSZ], cond[QBUFSZ]; register char *nb; - int hp, hpmax; - int cap = near_capacity(); + unsigned dln, dx, hln, xln, tln, cln; + int hp, hpmax, cap; + long money; + /* + * Various min(x,9999)'s are to avoid having excessive values + * violate the field width assumptions in botl.h and should not + * impact normal play [not too sure about limiting spell power + * to 3 digits]. Particularly 64-bit long for gold which could + * require many more digits if someone figures out a way to get + * and carry a really large (or negative) amount of it. + * Turn counter is also long, but we'll risk that. + */ + + /* dungeon location plus gold */ + (void) describe_level(dloc); /* includes at least one trailing space */ + if ((money = money_cnt(invent)) < 0L) + money = 0L; /* ought to issue impossible() and then discard gold */ + Sprintf(eos(dloc), "%s:%-2ld", + encglyph(objnum_to_glyph(GOLD_PIECE)), min(money, 999999L)); + dln = strlen(dloc); + /* '$' encoded as \GXXXXNNNN is 9 chars longer than display will need */ + dx = strstri(dloc, "\\G") ? 9 : 0; + + /* health and armor class (has trailing space for AC 0..9) */ hp = Upolyd ? u.mh : u.uhp; hpmax = Upolyd ? u.mhmax : u.uhpmax; - if (hp < 0) hp = 0; - (void) describe_level(newbot2); - Sprintf(nb = eos(newbot2), "%s:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", - encglyph(objnum_to_glyph(GOLD_PIECE)), money_cnt(invent), hp, - hpmax, u.uen, u.uenmax, u.uac); + Sprintf(hlth, "HP:%d(%d) Pw:%d(%d) AC:%-2d", + min(hp, 9999), min(hpmax, 9999), + min(u.uen, 999), min(u.uenmax, 999), u.uac); + hln = strlen(hlth); + /* experience */ if (Upolyd) - Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel); + Sprintf(expr, "HD:%d", mons[u.umonnum].mlevel); else if (flags.showexp) - Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel, u.uexp); + Sprintf(expr, "Xp:%u/%-1ld", u.ulevel, u.uexp); else - Sprintf(nb = eos(nb), " Exp:%u", u.ulevel); + Sprintf(expr, "Exp:%u", u.ulevel); + xln = strlen(expr); + /* time/move counter */ if (flags.time) - Sprintf(nb = eos(nb), " T:%ld", moves); - if (strcmp(hu_stat[u.uhs], " ")) { - Sprintf(nb = eos(nb), " "); - Strcat(newbot2, hu_stat[u.uhs]); - } - if (Confusion) - Sprintf(nb = eos(nb), " Conf"); + Sprintf(tmmv, "T:%ld", moves); + else + tmmv[0] = '\0'; + tln = strlen(tmmv); + + /* status conditions; worst ones first */ + cond[0] = '\0'; /* once non-empty, cond will have a leading space */ + nb = cond; + /* + * Stoned, Slimed, Strangled, and both types of Sick are all fatal + * unless remedied before timeout expires. Should we order them by + * shortest time left? [Probably not worth the effort, since it's + * unusual for more than one of them to apply at a time.] + */ + if (Stoned) + Strcpy(nb = eos(nb), " Stone"); + if (Slimed) + Strcpy(nb = eos(nb), " Slime"); + if (Strangled) + Strcpy(nb = eos(nb), " Strngl"); if (Sick) { if (u.usick_type & SICK_VOMITABLE) - Sprintf(nb = eos(nb), " FoodPois"); + Strcpy(nb = eos(nb), " FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) - Sprintf(nb = eos(nb), " Ill"); + Strcpy(nb = eos(nb), " TermIll"); } - if (Blind) - Sprintf(nb = eos(nb), " Blind"); - if (Stunned) - Sprintf(nb = eos(nb), " Stun"); - if (Hallucination) - Sprintf(nb = eos(nb), " Hallu"); - if (Slimed) - Sprintf(nb = eos(nb), " Slime"); - if (Deaf) - Sprintf(nb = eos(nb), " Df"); - if (cap > UNENCUMBERED) + if (u.uhs != NOT_HUNGRY) + Sprintf(nb = eos(nb), " %s", hu_stat[u.uhs]); + if ((cap = near_capacity()) > UNENCUMBERED) Sprintf(nb = eos(nb), " %s", enc_stat[cap]); + if (Blind) + Strcpy(nb = eos(nb), " Blind"); + if (Deaf) + Strcpy(nb = eos(nb), " Deaf"); + if (Stunned) + Strcpy(nb = eos(nb), " Stun"); + if (Confusion) + Strcpy(nb = eos(nb), " Conf"); + if (Hallucination) + Strcpy(nb = eos(nb), " Hallu"); + /* levitation and flying are mutually exclusive; riding is not */ + if (Levitation) + Strcpy(nb = eos(nb), " Lev"); + if (Flying) + Strcpy(nb = eos(nb), " Fly"); + if (u.usteed) + Strcpy(nb = eos(nb), " Ride"); + cln = strlen(cond); + + /* + * Put the pieces together. If they all fit, keep the traditional + * sequence. Otherwise, move least important parts to the end in + * case the interface side of things has to truncate. Note that + * dloc[] contains '$' encoded in ten character sequence \GXXXXNNNN + * so we want to test its display length rather than buffer length. + * + * We don't have an actual display limit here, so have to go by the + * width of the map. Since we're reordering rather than truncating, + * wider displays can still show wider status than the map if the + * interface supports that. + */ + if ((dln - dx) + 1 + hln + 1 + xln + 1 + tln + 1 + cln <= COLNO) { + Sprintf(newbot2, "%s %s %s %s %s", dloc, hlth, expr, tmmv, cond); + } else { + if (dln + 1 + hln + 1 + xln + 1 + tln + 1 + cln + 1 > MAXCO) { + panic("bot2: second status line exceeds MAXCO (%u > %d)", + (dln + 1 + hln + 1 + xln + 1 + tln + 1 + cln + 1), MAXCO); + } else if ((dln - dx) + 1 + hln + 1 + xln + 1 + cln <= COLNO) { + Sprintf(newbot2, "%s %s %s %s %s", dloc, hlth, expr, cond, tmmv); + } else if ((dln - dx) + 1 + hln + 1 + cln <= COLNO) { + Sprintf(newbot2, "%s %s %s %s %s", dloc, hlth, cond, expr, tmmv); + } else { + Sprintf(newbot2, "%s %s %s %s %s", hlth, cond, dloc, expr, tmmv); + } + /* only two or three consecutive spaces available to squeeze out */ + mungspaces(newbot2); + } + curs(WIN_STATUS, 1, 1); putmixed(WIN_STATUS, 0, newbot2); } @@ -302,11 +383,10 @@ struct istat_s { STATIC_DCL void NDECL(init_blstats); STATIC_DCL char *FDECL(anything_to_s, (char *, anything *, int)); -STATIC_DCL void FDECL(s_to_anything, (anything *, char *, int)); STATIC_OVL int FDECL(percentage, (struct istat_s *, struct istat_s *)); STATIC_OVL int FDECL(compare_blstats, (struct istat_s *, struct istat_s *)); - #ifdef STATUS_HILITES +STATIC_DCL void FDECL(s_to_anything, (anything *, char *, int)); STATIC_DCL boolean FDECL(assign_hilite, (char *, char *, char *, char *, BOOLEAN_P)); STATIC_DCL const char *FDECL(clridx_to_s, (char *, int)); @@ -340,35 +420,6 @@ STATIC_DCL struct istat_s initblstats[MAXBLSTATS] = { { (genericptr_t) 0 }, (char *) 0, 0, 0, BL_CONDITION} }; -static struct fieldid_t { - const char *fieldname; - enum statusfields fldid; -} fieldids[] = { - {"title", BL_TITLE}, - {"strength", BL_STR}, - {"dexterity", BL_DX}, - {"constitution", BL_CO}, - {"intelligence", BL_IN}, - {"wisdom", BL_WI}, - {"charisma", BL_CH}, - {"alignment", BL_ALIGN}, - {"score", BL_SCORE}, - {"carrying-capacity", BL_CAP}, - {"gold", BL_GOLD}, - {"power", BL_ENE}, - {"power-max", BL_ENEMAX}, - {"experience-level", BL_XP}, - {"armor-class", BL_AC}, - {"HD", BL_HD}, - {"time", BL_TIME}, - {"hunger", BL_HUNGER}, - {"hitpoints", BL_HP}, - {"hitpoints-max", BL_HPMAX}, - {"dungeon-level", BL_LEVELDESC}, - {"experience", BL_EXP}, - {"condition", BL_CONDITION}, -}; - struct istat_s blstats[2][MAXBLSTATS]; static boolean blinit = FALSE, update_all = FALSE; @@ -378,11 +429,11 @@ bot() char buf[BUFSZ]; register char *nb; static int idx = 0, idx_p, idxmax; - boolean updated = FALSE; unsigned anytype; + long money; int i, pc, chg, cap; struct istat_s *curr, *prev; - boolean valset[MAXBLSTATS], chgval = FALSE; + boolean valset[MAXBLSTATS], chgval = FALSE, updated = FALSE; if (!blinit) panic("bot before init."); @@ -392,41 +443,35 @@ bot() return; } - cap = near_capacity(); idx_p = idx; idx = 1 - idx; /* 0 -> 1, 1 -> 0 */ /* clear the "value set" indicators */ - (void) memset((genericptr_t) valset, 0, MAXBLSTATS * sizeof(boolean)); + (void) memset((genericptr_t) valset, 0, MAXBLSTATS * sizeof (boolean)); + + /* + * Note: min(x,9999) - we enforce the same maximum on hp, maxhp, + * pw, maxpw, and gold as basic status formatting so that the two + * modes of status display don't produce different information. + */ /* * Player name and title. */ - buf[0] = '\0'; - Strcpy(buf, plname); - if ('a' <= buf[0] && buf[0] <= 'z') - buf[0] += 'A' - 'a'; - buf[10] = 0; - Sprintf(nb = eos(buf), " the "); + Strcpy(nb = buf, plname); + nb[0] = highc(nb[0]); + nb[10] = '\0'; + Sprintf(nb = eos(nb), " the "); if (Upolyd) { - char mbot[BUFSZ]; - int k = 0; - - Strcpy(mbot, mons[u.umonnum].mname); - while (mbot[k] != 0) { - if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k] - && mbot[k] <= 'z') - mbot[k] += 'A' - 'a'; - k++; - } - Sprintf1(nb = eos(nb), mbot); + for (i = 0, nb = strcpy(eos(nb), mons[u.umonnum].mname); nb[i]; i++) + if (i == 0 || nb[i - 1] == ' ') + nb[i] = highc(nb[i]); } else - Sprintf1(nb = eos(nb), rank()); + Strcpy(nb = eos(nb), rank()); Sprintf(blstats[idx][BL_TITLE].val, "%-29s", buf); valset[BL_TITLE] = TRUE; /* indicate val already set */ /* Strength */ - buf[0] = '\0'; blstats[idx][BL_STR].a.a_int = ACURR(A_STR); if (ACURR(A_STR) > 18) { @@ -442,7 +487,6 @@ bot() valset[BL_STR] = TRUE; /* indicate val already set */ /* Dexterity, constitution, intelligence, wisdom, charisma. */ - blstats[idx][BL_DX].a.a_int = ACURR(A_DEX); blstats[idx][BL_CO].a.a_int = ACURR(A_CON); blstats[idx][BL_IN].a.a_int = ACURR(A_INT); @@ -450,135 +494,119 @@ bot() blstats[idx][BL_CH].a.a_int = ACURR(A_CHA); /* Alignment */ - - Strcpy(blstats[idx][BL_ALIGN].val, - (u.ualign.type == A_CHAOTIC) - ? "Chaotic" - : (u.ualign.type == A_NEUTRAL) ? "Neutral" : "Lawful"); + Strcpy(blstats[idx][BL_ALIGN].val, (u.ualign.type == A_CHAOTIC) + ? "Chaotic" + : (u.ualign.type == A_NEUTRAL) + ? "Neutral" + : "Lawful"); /* Score */ - blstats[idx][BL_SCORE].a.a_long = #ifdef SCORE_ON_BOTL - botl_score(); + botl_score() #else - 0; + 0L #endif - /* Hit points */ + ; - blstats[idx][BL_HP].a.a_int = Upolyd ? u.mh : u.uhp; - blstats[idx][BL_HPMAX].a.a_int = Upolyd ? u.mhmax : u.uhpmax; - if (blstats[idx][BL_HP].a.a_int < 0) - blstats[idx][BL_HP].a.a_int = 0; + /* Hit points */ + i = Upolyd ? u.mh : u.uhp; + if (i < 0) + i = 0; + blstats[idx][BL_HP].a.a_int = min(i, 9999); + i = Upolyd ? u.mhmax : u.uhpmax; + blstats[idx][BL_HPMAX].a.a_int = min(i, 9999); /* Dungeon level. */ - (void) describe_level(blstats[idx][BL_LEVELDESC].val); valset[BL_LEVELDESC] = TRUE; /* indicate val already set */ /* Gold */ - - blstats[idx][BL_GOLD].a.a_long = money_cnt(invent); + if ((money = money_cnt(invent)) < 0L) + money = 0L; /* ought to issue impossible() and then discard gold */ + blstats[idx][BL_GOLD].a.a_long = min(money, 999999L); /* * The tty port needs to display the current symbol for gold * as a field header, so to accommodate that we pass gold with * that already included. If a window port needs to use the text * gold amount without the leading "$:" the port will have to - * add 2 to the value pointer it was passed in status_update() + * skip past ':' to the value pointer it was passed in status_update() * for the BL_GOLD case. * * Another quirk of BL_GOLD is that the field display may have * changed if a new symbol set was loaded, or we entered or left * the rogue level. + * + * The currency prefix is encoded as ten character \GXXXXNNNN + * sequence. */ - Sprintf(blstats[idx][BL_GOLD].val, "%s:%ld", encglyph(objnum_to_glyph(GOLD_PIECE)), blstats[idx][BL_GOLD].a.a_long); valset[BL_GOLD] = TRUE; /* indicate val already set */ /* Power (magical energy) */ - - blstats[idx][BL_ENE].a.a_int = u.uen; - blstats[idx][BL_ENEMAX].a.a_int = u.uenmax; + blstats[idx][BL_ENE].a.a_int = min(u.uen, 999); + blstats[idx][BL_ENEMAX].a.a_int = min(u.uenmax, 999); /* Armor class */ - blstats[idx][BL_AC].a.a_int = u.uac; /* Monster level (if Upolyd) */ - - if (Upolyd) - blstats[idx][BL_HD].a.a_int = mons[u.umonnum].mlevel; - else - blstats[idx][BL_HD].a.a_int = 0; + blstats[idx][BL_HD].a.a_int = Upolyd ? mons[u.umonnum].mlevel : 0; /* Experience */ - blstats[idx][BL_XP].a.a_int = u.ulevel; blstats[idx][BL_EXP].a.a_int = u.uexp; /* Time (moves) */ - blstats[idx][BL_TIME].a.a_long = moves; /* Hunger */ - blstats[idx][BL_HUNGER].a.a_uint = u.uhs; - *(blstats[idx][BL_HUNGER].val) = '\0'; - if (strcmp(hu_stat[u.uhs], " ") != 0) - Strcpy(blstats[idx][BL_HUNGER].val, hu_stat[u.uhs]); + Strcpy(blstats[idx][BL_HUNGER].val, + (u.uhs != NOT_HUNGRY) ? hu_stat[u.uhs] : ""); valset[BL_HUNGER] = TRUE; /* Carrying capacity */ - - *(blstats[idx][BL_CAP].val) = '\0'; + cap = near_capacity(); blstats[idx][BL_CAP].a.a_int = cap; - if (cap > UNENCUMBERED) - Strcpy(blstats[idx][BL_CAP].val, enc_stat[cap]); + Strcpy(blstats[idx][BL_CAP].val, + (cap > UNENCUMBERED) ? enc_stat[cap] : ""); valset[BL_CAP] = TRUE; /* Conditions */ - + blstats[idx][BL_CONDITION].a.a_ulong = 0L; + if (Stoned) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_STONE; + if (Slimed) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_SLIME; + if (Strangled) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_STRNGL; + if (Sick && (u.usick_type & SICK_VOMITABLE) != 0) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_FOODPOIS; + if (Sick && (u.usick_type & SICK_NONVOMITABLE) != 0) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_TERMILL; + /* + * basic formatting puts hunger status and encumbrance here + */ if (Blind) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_BLIND; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_BLIND; - if (Deaf) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_DEAF; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_DEAF; - + if (Stunned) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_STUN; if (Confusion) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_CONF; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_CONF; - - if (Sick && u.usick_type & SICK_VOMITABLE) - blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_FOODPOIS; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_FOODPOIS; - - if (Sick && u.usick_type & SICK_NONVOMITABLE) - blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_ILL; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_ILL; - if (Hallucination) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_HALLU; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_HALLU; - - if (Stunned) - blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_STUNNED; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_STUNNED; - - if (Slimed) - blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_SLIMED; - else - blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_SLIMED; + /* levitation and flying are mututally exclusive */ + if (Levitation) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_LEV; + if (Flying) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_FLY; + if (u.usteed) + blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_RIDE; /* * Now pass the changed values to window port. @@ -594,10 +622,11 @@ bot() curr = &blstats[idx][i]; prev = &blstats[idx_p][i]; chg = 0; - if (update_all || ((chg = compare_blstats(prev, curr)) != 0) - || ((chgval = (valset[i] && strcmp(blstats[idx][i].val, - blstats[idx_p][i].val))) - != 0)) { + if (update_all + || ((chg = compare_blstats(prev, curr)) != 0) + || ((chgval = (valset[i] + && strcmp(blstats[idx][i].val, + blstats[idx_p][i].val))) != 0)) { idxmax = blstats[idx][i].idxmax; pc = (idxmax) ? percentage(curr, &blstats[idx][idxmax]) : 0; if (!valset[i]) @@ -606,9 +635,8 @@ bot() status_update(i, (genericptr_t) curr->val, valset[i] ? chgval : chg, pc); } else { - status_update(i, - /* send pointer to mask */ - (genericptr_t) &curr->a.a_ulong, chg, 0); + /* send pointer to mask */ + status_update(i, (genericptr_t) &curr->a.a_ulong, chg, 0); } updated = TRUE; } @@ -637,8 +665,8 @@ boolean reassessment; /* TRUE = just reassess fields w/o other initialization*/ { int i; - const char *fieldfmt = (const char *)0; - const char *fieldname = (const char *)0; + const char *fieldfmt = (const char *) 0; + const char *fieldname = (const char *) 0; if (!reassessment) { init_blstats(); @@ -868,6 +896,8 @@ int anytype; return buf; } +#ifdef STATUS_HILITES + STATIC_OVL void s_to_anything(a, buf, anytype) anything *a; @@ -916,6 +946,8 @@ int anytype; return; } +#endif + STATIC_OVL int compare_blstats(bl1, bl2) struct istat_s *bl1, *bl2; @@ -1047,6 +1079,35 @@ struct istat_s *bl, *maxbl; /* Core status hiliting support */ /****************************************************************************/ +static struct fieldid_t { + const char *fieldname; + enum statusfields fldid; +} fieldids[] = { + {"title", BL_TITLE}, + {"strength", BL_STR}, + {"dexterity", BL_DX}, + {"constitution", BL_CO}, + {"intelligence", BL_IN}, + {"wisdom", BL_WI}, + {"charisma", BL_CH}, + {"alignment", BL_ALIGN}, + {"score", BL_SCORE}, + {"carrying-capacity", BL_CAP}, + {"gold", BL_GOLD}, + {"power", BL_ENE}, + {"power-max", BL_ENEMAX}, + {"experience-level", BL_XP}, + {"armor-class", BL_AC}, + {"HD", BL_HD}, + {"time", BL_TIME}, + {"hunger", BL_HUNGER}, + {"hitpoints", BL_HP}, + {"hitpoints-max", BL_HPMAX}, + {"dungeon-level", BL_LEVELDESC}, + {"experience", BL_EXP}, + {"condition", BL_CONDITION}, +}; + struct hilite_s { boolean set; unsigned anytype; @@ -1118,6 +1179,7 @@ boolean from_configfile; { int i; anything it; + it = zeroany; for (i = 0; i < MAXBLSTATS; ++i) { (void) memset((genericptr_t) &status_hilites[i], 0, @@ -1196,15 +1258,11 @@ boolean from_configfile; /* actions */ for (i = 0; i < 2; ++i) { - if (!i) - how = sc; - else - how = sd; + how = !i ? sc : sd; if (!how) { if (!i) return FALSE; - else - break; /* sc is mandatory; sd is not */ + break; /* sc is mandatory; sd is not */ } if (strcmpi(how, "bold") == 0) { @@ -1215,6 +1273,7 @@ boolean from_configfile; normal[i] = TRUE; } else { int k = match_str2clr(how); + if (k >= CLR_MAX) return FALSE; coloridx[i] = k; @@ -1271,10 +1330,10 @@ boolean all; for (idx = 0; idx < MAXBLSTATS; ++idx) { if (status_hilites[idx].set) status_threshold(idx, status_hilites[idx].anytype, - status_hilites[idx].threshold, - status_hilites[idx].behavior, - status_hilites[idx].coloridx[0], - status_hilites[idx].coloridx[1]); + status_hilites[idx].threshold, + status_hilites[idx].behavior, + status_hilites[idx].coloridx[0], + status_hilites[idx].coloridx[1]); else status_threshold(idx, blstats[0][idx].anytype, it, 0, 0, 0); @@ -1358,6 +1417,7 @@ int bufsiz; text = "normal"; } else { char *blank; + (void) strcpy(colorname, c_obj_colors[coloridx]); for (blank = index(colorname, ' '); blank; blank = index(colorname, ' ')) @@ -1434,6 +1494,7 @@ status_hilite_menu() for (i = 0; i < MAXBLSTATS; i++) { if (field_picks[i]) { menu_item *pick = (menu_item *) 0; + Sprintf(buf, "Threshold behavior options for %s:", fieldids[i].fieldname); tmpwin = create_nhwindow(NHW_MENU); diff --git a/src/do_wear.c b/src/do_wear.c index ea73cace8..bedda5298 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -730,8 +730,9 @@ Amulet_on() case AMULET_OF_STRANGULATION: if (can_be_strangled(&youmonst)) { makeknown(AMULET_OF_STRANGULATION); - pline("It constricts your throat!"); Strangled = 6L; + context.botl = TRUE; + pline("It constricts your throat!"); } break; case AMULET_OF_RESTFUL_SLEEP: { @@ -780,11 +781,12 @@ Amulet_off() break; case AMULET_OF_STRANGULATION: if (Strangled) { + Strangled = 0L; + context.botl = TRUE; if (Breathless) Your("%s is no longer constricted!", body_part(NECK)); else You("can breathe more easily!"); - Strangled = 0L; } break; case AMULET_OF_RESTFUL_SLEEP: diff --git a/src/polyself.c b/src/polyself.c index 9cdc83be8..68936af8d 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -114,6 +114,7 @@ float_vs_flight() BFlying |= I_SPECIAL; else BFlying &= ~I_SPECIAL; + context.botl = TRUE; } /* for changing into form that's immune to strangulation */ @@ -127,10 +128,11 @@ boolean on; vulnerable form into another causes the counter to be reset */ if (uamul && uamul->otyp == AMULET_OF_STRANGULATION && can_be_strangled(&youmonst)) { + Strangled = 6L; + context.botl = TRUE; Your("%s %s your %s!", simpleonames(uamul), Strangled ? "still constricts" : "begins constricting", body_part(NECK)); /* "throat" */ - Strangled = 6L; makeknown(AMULET_OF_STRANGULATION); } @@ -138,6 +140,7 @@ boolean on; } else { if (Strangled && !can_be_strangled(&youmonst)) { Strangled = 0L; + context.botl = TRUE; You("are no longer being strangled."); } } diff --git a/src/potion.c b/src/potion.c index 2a54d5fa1..484b89806 100644 --- a/src/potion.c +++ b/src/potion.c @@ -165,12 +165,12 @@ const char *msg; if (Unaware) msg = 0; #endif - if ((!xtime && old) || (xtime && !old)) { + set_itimeout(&Slimed, xtime); + if ((xtime != 0L) ^ (old != 0L)) { + context.botl = TRUE; if (msg) pline1(msg); - context.botl = 1; } - set_itimeout(&Slimed, xtime); if (!Slimed) dealloc_killer(find_delayed_killer(SLIMED)); } @@ -189,12 +189,12 @@ const char *killername; if (Unaware) msg = 0; #endif - if ((!xtime && old) || (xtime && !old)) { + set_itimeout(&Stoned, xtime); + if ((xtime != 0L) ^ (old != 0L)) { + context.botl = TRUE; if (msg) pline1(msg); - /* context.botl = 1; --- Stoned is not a status line item */ } - set_itimeout(&Stoned, xtime); if (!Stoned) dealloc_killer(find_delayed_killer(STONED)); else if (!old) @@ -211,11 +211,11 @@ boolean talk; if (Unaware) talk = FALSE; + set_itimeout(&Vomiting, xtime); + context.botl = TRUE; if (!xtime && old) if (talk) You_feel("much less nauseated now."); - - set_itimeout(&Vomiting, xtime); } static const char vismsg[] = "vision seems to %s for a moment but is %s now."; @@ -292,7 +292,7 @@ boolean talk; set_itimeout(&Blinded, xtime); if (u_could_see ^ can_see_now) { /* one or the other but not both */ - context.botl = 1; + context.botl = TRUE; vision_full_recalc = 1; /* blindness just got toggled */ /* this vision recalculation used to be deferred until moveloop(), but that made it possible for vision @@ -383,7 +383,7 @@ long mask; /* nonzero if resistance status should change by mask */ (eg. Qt windowport's equipped items display) */ update_inventory(); - context.botl = 1; + context.botl = TRUE; if (talk) pline(message, verb); } @@ -396,25 +396,16 @@ long xtime; boolean talk; { long old = HDeaf; - boolean toggled = FALSE; if (Unaware) talk = FALSE; - if (!xtime && old) { - if (talk) - You("can hear again."); - toggled = TRUE; - } else if (xtime && !old) { - if (talk) - You("are unable to hear anything."); - toggled = TRUE; - } - /* request a status update */ - if (toggled) - context.botl = TRUE; - set_itimeout(&HDeaf, xtime); + if ((xtime != 0L) ^ (old != 0L)) { + context.botl = TRUE; + if (talk) + You(old ? "can hear again." : "are unable to hear anything."); + } } STATIC_OVL void diff --git a/src/steed.c b/src/steed.c index 1129a27cc..4070bbf74 100644 --- a/src/steed.c +++ b/src/steed.c @@ -285,7 +285,7 @@ boolean force; /* Quietly force this animal */ } if (!can_saddle(mtmp) || !can_ride(mtmp)) { You_cant("ride such a creature."); - return (0); + return FALSE; } /* Is the player impaired? */ @@ -332,7 +332,8 @@ boolean force; /* Quietly force this animal */ u.usteed = mtmp; remove_monster(mtmp->mx, mtmp->my); teleds(mtmp->mx, mtmp->my, TRUE); - return (TRUE); + context.botl = TRUE; + return TRUE; } /* You and your steed have moved */ @@ -610,11 +611,11 @@ int reason; /* Player was thrown off etc. */ in_steed_dismounting = TRUE; (void) float_down(0L, W_SADDLE); in_steed_dismounting = FALSE; - context.botl = 1; + context.botl = TRUE; (void) encumber_msg(); vision_full_recalc = 1; } else - context.botl = 1; + context.botl = TRUE; /* polearms behave differently when not mounted */ if (uwep && is_pole(uwep)) unweapon = TRUE; diff --git a/src/trap.c b/src/trap.c index 80f638e90..91bc589d3 100644 --- a/src/trap.c +++ b/src/trap.c @@ -2733,6 +2733,7 @@ boolean byplayer; void float_up() { + context.botl = TRUE; if (u.utrap) { if (u.utraptype == TT_PIT) { u.utrap = 0; @@ -2811,6 +2812,7 @@ long hmask, emask; /* might cancel timeout */ float_vs_flight(); /* before nomul() rather than after */ return 0; } + context.botl = TRUE; nomul(0); /* stop running or resting */ if (BFlying) { /* controlled flight no longer overridden by levitation */ diff --git a/src/windows.c b/src/windows.c index 1423f8cf1..ce6691347 100644 --- a/src/windows.c +++ b/src/windows.c @@ -751,8 +751,9 @@ hup_get_color_string(VOID_ARGS) /*ARGSUSED*/ static void hup_status_update(idx, ptr, chg, percent) -int idx UNUSED, chg UNUSED, percent UNUSED; +int idx UNUSED; genericptr_t ptr UNUSED; +int chg UNUSED, percent UNUSED; { return; } @@ -855,8 +856,9 @@ boolean enable; void genl_status_update(idx, ptr, chg, percent) -int idx, chg, percent; +int idx; genericptr_t ptr; +int chg UNUSED, percent UNUSED; { char newbot1[MAXCO], newbot2[MAXCO]; long cond, *condptr = (long *) ptr; @@ -879,20 +881,32 @@ genericptr_t ptr; case BL_CONDITION: cond = *condptr; *status_vals[idx] = '\0'; - if (cond & BL_MASK_BLIND) - Strcat(status_vals[idx], " Blind"); - if (cond & BL_MASK_CONF) - Strcat(status_vals[idx], " Conf"); + if (cond & BL_MASK_STONE) + Strcat(status_vals[idx], " Stone"); + if (cond & BL_MASK_SLIME) + Strcat(status_vals[idx], " Slime"); + if (cond & BL_MASK_STRNGL) + Strcat(status_vals[idx], " Strngl"); if (cond & BL_MASK_FOODPOIS) Strcat(status_vals[idx], " FoodPois"); - if (cond & BL_MASK_ILL) - Strcat(status_vals[idx], " Ill"); - if (cond & BL_MASK_STUNNED) + if (cond & BL_MASK_TERMILL) + Strcat(status_vals[idx], " TermIll"); + if (cond & BL_MASK_BLIND) + Strcat(status_vals[idx], " Blind"); + if (cond & BL_MASK_DEAF) + Strcat(status_vals[idx], " Deaf"); + if (cond & BL_MASK_STUN) Strcat(status_vals[idx], " Stun"); + if (cond & BL_MASK_CONF) + Strcat(status_vals[idx], " Conf"); if (cond & BL_MASK_HALLU) Strcat(status_vals[idx], " Hallu"); - if (cond & BL_MASK_SLIMED) - Strcat(status_vals[idx], " Slime"); + if (cond & BL_MASK_LEV) + Strcat(status_vals[idx], " Lev"); + if (cond & BL_MASK_FLY) + Strcat(status_vals[idx], " Fly"); + if (cond & BL_MASK_RIDE) + Strcat(status_vals[idx], " Ride"); break; default: Sprintf(status_vals[idx], diff --git a/win/tty/wintty.c b/win/tty/wintty.c index acd1b86ad..82f96f1b0 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3387,17 +3387,23 @@ tty_status_init() * -- ptr is usually a "char *", unless fldindex is BL_CONDITION. * If fldindex is BL_CONDITION, then ptr is a long value with * any or none of the following bits set (from botl.h): - * BL_MASK_BLIND 0x00000001L - * BL_MASK_CONF 0x00000002L - * BL_MASK_FOODPOIS 0x00000004L - * BL_MASK_ILL 0x00000008L - * BL_MASK_HALLU 0x00000010L - * BL_MASK_STUNNED 0x00000020L - * BL_MASK_SLIMED 0x00000040L - * -- The value passed for BL_GOLD includes a leading - * symbol for GOLD "$:nnn". If the window port needs to use - * the textual gold amount without the leading "$:" the port - * will have to add 2 to the passed "ptr" for the BL_GOLD case. + * BL_MASK_STONE 0x00000001L + * BL_MASK_SLIME 0x00000002L + * BL_MASK_STRNGL 0x00000004L + * BL_MASK_FOODPOIS 0x00000008L + * BL_MASK_TERMILL 0x00000010L + * BL_MASK_BLIND 0x00000020L + * BL_MASK_DEAF 0x00000040L + * BL_MASK_STUN 0x00000080L + * BL_MASK_CONF 0x00000100L + * BL_MASK_HALLU 0x00000200L + * BL_MASK_LEV 0x00000400L + * BL_MASK_FLY 0x00000800L + * BL_MASK_RIDE 0x00001000L + * -- The value passed for BL_GOLD includes an encoded leading + * symbol for GOLD "\GXXXXNNNN:nnn". If the window port needs to use + * the textual gold amount without the leading "$:" the port will + * have to skip past ':' in the passed "ptr" for the BL_GOLD case. */ void tty_status_update(fldidx, ptr, chg, percent) @@ -3412,8 +3418,6 @@ genericptr_t ptr; * BL_HILITE_INVERSE -2 + 3 = 1 (statusattr[1]) * BL_HILITE_BOLD -3 + 3 = 0 (statusattr[0]) */ - int statusattr[] = { ATR_BOLD, ATR_INVERSE, ATR_NONE }; - int attridx = 0; long value = -1L; static boolean beenhere = FALSE; enum statusfields fieldorder[2][15] = { @@ -3424,6 +3428,13 @@ genericptr_t ptr; BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; +#ifdef STATUS_HILITES + static int statusattr[] = { ATR_BOLD, ATR_INVERSE, ATR_NONE }; + int attridx = 0; +#else + nhUse(chg); + nhUse(percent); +#endif if (fldidx != BL_FLUSH) { if (!status_activefields[fldidx]) @@ -3432,20 +3443,32 @@ genericptr_t ptr; case BL_CONDITION: cond = *condptr; *status_vals[fldidx] = '\0'; - if (cond & BL_MASK_BLIND) - Strcat(status_vals[fldidx], " Blind"); - if (cond & BL_MASK_CONF) - Strcat(status_vals[fldidx], " Conf"); + if (cond & BL_MASK_STONE) + Strcat(status_vals[fldidx], " Stone"); + if (cond & BL_MASK_SLIME) + Strcat(status_vals[fldidx], " Slime"); + if (cond & BL_MASK_STRNGL) + Strcat(status_vals[fldidx], " Strngl"); if (cond & BL_MASK_FOODPOIS) Strcat(status_vals[fldidx], " FoodPois"); - if (cond & BL_MASK_ILL) - Strcat(status_vals[fldidx], " Ill"); - if (cond & BL_MASK_STUNNED) + if (cond & BL_MASK_TERMILL) + Strcat(status_vals[fldidx], " TermIll"); + if (cond & BL_MASK_BLIND) + Strcat(status_vals[fldidx], " Blind"); + if (cond & BL_MASK_DEAF) + Strcat(status_vals[fldidx], " Deaf"); + if (cond & BL_MASK_STUN) Strcat(status_vals[fldidx], " Stun"); + if (cond & BL_MASK_CONF) + Strcat(status_vals[fldidx], " Conf"); if (cond & BL_MASK_HALLU) Strcat(status_vals[fldidx], " Hallu"); - if (cond & BL_MASK_SLIMED) - Strcat(status_vals[fldidx], " Slime"); + if (cond & BL_MASK_LEV) + Strcat(status_vals[fldidx], " Lev"); + if (cond & BL_MASK_FLY) + Strcat(status_vals[fldidx], " Fly"); + if (cond & BL_MASK_RIDE) + Strcat(status_vals[fldidx], " Ride"); value = cond; break; default: @@ -3554,23 +3577,26 @@ genericptr_t ptr; int fldidx1 = fieldorder[0][i]; if (status_activefields[fldidx1]) { - if (tty_status_colors[fldidx1] < 0 && - tty_status_colors[fldidx1] >= -3) { +#ifdef STATUS_HILITES + if (tty_status_colors[fldidx1] < 0 + && tty_status_colors[fldidx1] >= -3) { /* attribute, not a color */ attridx = tty_status_colors[fldidx1] + 3; term_start_attr(statusattr[attridx]); putstr(WIN_STATUS, 0, status_vals[fldidx1]); term_end_attr(statusattr[attridx]); + } else #ifdef TEXTCOLOR - } else if (tty_status_colors[fldidx1] != CLR_MAX) { + if (tty_status_colors[fldidx1] != CLR_MAX) { if (tty_status_colors[fldidx1] != NO_COLOR) term_start_color(tty_status_colors[fldidx1]); putstr(WIN_STATUS, 0, status_vals[fldidx1]); if (tty_status_colors[fldidx1] != NO_COLOR) term_end_color(); -#endif } else - putstr(WIN_STATUS, 0, status_vals[fldidx1]); +#endif +#endif /* STATUS_HILITES */ + putstr(WIN_STATUS, 0, status_vals[fldidx1]); } } curs(WIN_STATUS, 1, 1); @@ -3578,28 +3604,31 @@ genericptr_t ptr; int fldidx2 = fieldorder[1][i]; if (status_activefields[fldidx2]) { - if (tty_status_colors[fldidx2] < 0 && - tty_status_colors[fldidx2] >= -3) { +#ifdef STATUS_HILITES + if (tty_status_colors[fldidx2] < 0 + && tty_status_colors[fldidx2] >= -3) { /* attribute, not a color */ attridx = tty_status_colors[fldidx2] + 3; term_start_attr(statusattr[attridx]); putstr(WIN_STATUS, 0, status_vals[fldidx2]); term_end_attr(statusattr[attridx]); + } else #ifdef TEXTCOLOR - } else if (tty_status_colors[fldidx2] != CLR_MAX) { + if (tty_status_colors[fldidx2] != CLR_MAX) { if (tty_status_colors[fldidx2] != NO_COLOR) term_start_color(tty_status_colors[fldidx2]); if (fldidx2 == BL_GOLD) { /* putmixed() due to GOLD glyph */ - putmixed(WIN_STATUS, 0, status_vals[fldidx2]); + putmixed(WIN_STATUS, 0, status_vals[fldidx2]); } else { - putstr(WIN_STATUS, 0, status_vals[fldidx2]); + putstr(WIN_STATUS, 0, status_vals[fldidx2]); } if (tty_status_colors[fldidx2] != NO_COLOR) term_end_color(); -#endif } else - putstr(WIN_STATUS, 0, status_vals[fldidx2]); +#endif +#endif /* STATUS_HILITES */ + putstr(WIN_STATUS, 0, status_vals[fldidx2]); } } return; diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 073cd1501..a483bf223 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -2819,18 +2819,23 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percentage) -- ptr is usually a "char *", unless fldindex is BL_CONDITION. If fldindex is BL_CONDITION, then ptr is a long value with any or none of the following bits set (from botl.h): - BL_MASK_BLIND 0x00000001L - BL_MASK_CONF 0x00000002L - BL_MASK_FOODPOIS 0x00000004L - BL_MASK_ILL 0x00000008L - BL_MASK_HALLU 0x00000010L - BL_MASK_STUNNED 0x00000020L - BL_MASK_SLIMED 0x00000040L - -- The value passed for BL_GOLD includes a leading - symbol for GOLD "$:nnn". If the window port needs to use - the textual gold amount without the leading "$:" the port - will have to add 2 to the passed "ptr" for the BL_GOLD -case. + BL_MASK_STONE 0x00000001L + BL_MASK_SLIME 0x00000002L + BL_MASK_STRNGL 0x00000004L + BL_MASK_FOODPOIS 0x00000008L + BL_MASK_TERMILL 0x00000010L + BL_MASK_BLIND 0x00000020L + BL_MASK_DEAF 0x00000040L + BL_MASK_STUN 0x00000080L + BL_MASK_CONF 0x00000100L + BL_MASK_HALLU 0x00000200L + BL_MASK_LEV 0x00000400L + BL_MASK_FLY 0x00000800L + BL_MASK_RIDE 0x00001000L + -- The value passed for BL_GOLD includes an encoded leading + symbol for GOLD "\GXXXXNNNN:nnn". If window port needs + textual gold amount without the leading "$:" the port will + have to skip past ':' in passed "ptr" for the BL_GOLD case. */ void mswin_status_update(int idx, genericptr_t ptr, int chg, int percent) @@ -2851,20 +2856,32 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent) case BL_CONDITION: { cond = *condptr; *_status_vals[idx] = '\0'; - if (cond & BL_MASK_BLIND) - Strcat(_status_vals[idx], " Blind"); - if (cond & BL_MASK_CONF) - Strcat(_status_vals[idx], " Conf"); + if (cond & BL_MASK_STONE) + Strcat(_status_vals[idx], " Stone"); + if (cond & BL_MASK_SLIME) + Strcat(_status_vals[idx], " Slime"); + if (cond & BL_MASK_STRNGL) + Strcat(_status_vals[idx], " Strngl"); if (cond & BL_MASK_FOODPOIS) Strcat(_status_vals[idx], " FoodPois"); - if (cond & BL_MASK_ILL) - Strcat(_status_vals[idx], " Ill"); - if (cond & BL_MASK_STUNNED) + if (cond & BL_MASK_TERMILL) + Strcat(_status_vals[idx], " TermIll"); + if (cond & BL_MASK_BLIND) + Strcat(_status_vals[idx], " Blind"); + if (cond & BL_MASK_DEAF) + Strcat(_status_vals[idx], " Deaf"); + if (cond & BL_MASK_STUN) Strcat(_status_vals[idx], " Stun"); + if (cond & BL_MASK_CONF) + Strcat(_status_vals[idx], " Conf"); if (cond & BL_MASK_HALLU) Strcat(_status_vals[idx], " Hallu"); - if (cond & BL_MASK_SLIMED) - Strcat(_status_vals[idx], " Slime"); + if (cond & BL_MASK_LEV) + Strcat(_status_vals[idx], " Lev"); + if (cond & BL_MASK_FLY) + Strcat(_status_vals[idx], " Fly"); + if (cond & BL_MASK_RIDE) + Strcat(_status_vals[idx], " Ride"); value = cond; } break; case BL_GOLD: {