diff --git a/dat/data.base b/dat/data.base index 960932c18..50152f2c1 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/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/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 # diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 2efd8bbf2..44dc33b29 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. @@ -2121,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 @@ -2218,6 +2227,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..88a9d8eb6 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. @@ -2553,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). @@ -2664,6 +2676,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 2602460c0..96c0ee768 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 @@ -97,6 +98,17 @@ 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 +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 +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 @@ -105,7 +117,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) @@ -142,10 +154,17 @@ 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 +allow showing coordinates when picking a position on the map and + autodescribe option is on 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 3392e6407..121ce5407 100644 --- a/include/config.h +++ b/include/config.h @@ -439,6 +439,39 @@ 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 */ + +/* 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 */ @@ -459,6 +492,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/extern.h b/include/extern.h index 3e58ee565..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)); @@ -1662,7 +1663,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/include/flag.h b/include/flag.h index bd6d2b2fc..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 */ @@ -199,6 +205,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 */ @@ -258,6 +265,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/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 }, 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/do_name.c b/src/do_name.c index da48c07dc..3c86589c2 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,54 +102,81 @@ coord **arr_p; int *cnt_p; boolean do_mons; { - int x, y, pass, glyph, idx; + 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); - 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 */ + 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); } +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; @@ -193,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); } @@ -294,51 +336,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]; 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)); 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)) { diff --git a/src/mon.c b/src/mon.c index 08333c250..802d20bff 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 @@ -3144,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) { diff --git a/src/options.c b/src/options.c index 11a26c074..6ba023a3c 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 }, @@ -220,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 @@ -284,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*/ @@ -675,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 = @@ -1455,8 +1467,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 +1478,7 @@ const char *msg; return tmp->msgtype; tmp = tmp->next; } - return MSGTYP_NORMAL; + return norepeat ? MSGTYP_NOREP : MSGTYP_NORMAL; } int @@ -2321,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) @@ -3997,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 */ @@ -4744,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" : ""); diff --git a/src/pline.c b/src/pline.c index ce4b60702..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 @@ -83,22 +86,27 @@ 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); + +#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); - 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 @@ -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/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); diff --git a/src/wizard.c b/src/wizard.c index facacc799..57d4d6cbe 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 = 0, sy = 0; 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)) diff --git a/src/zap.c b/src/zap.c index 0749c8dbf..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) @@ -4234,8 +4238,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 +4249,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); 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\" diff --git a/util/makedefs.c b/util/makedefs.c index 0e340b478..a20660c7c 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 @@ -1347,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 diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 58dee65a3..acd1b86ad 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) { @@ -2108,13 +2151,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 @@ -2143,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) @@ -2212,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 @@ -2300,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: @@ -2367,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 */ @@ -3063,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) ' '); @@ -3109,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 */ } @@ -3119,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 @@ -3133,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); @@ -3162,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 @@ -3184,6 +3246,14 @@ 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 */ + int tmp = vt_tile_current_window; + vt_tile_current_window++; + print_vt_code2(AVTC_SELECT_WINDOW, tmp); + } +#endif /* TTY_TILES_ESCCODES */ return i; }